在 Elixir 中枚举一个字符串
Enumerate a string in Elixir
在 Elixir 中,如果我有一个字符串,例如 "José1 José2"
,我该如何枚举它?如果我尝试使用 Enum
或 for
理解,我会收到以下错误:
** (Protocol.UndefinedError) protocol Enumerable not implemented for "José1 José2" of type BitString
Elixir 中的字符串是 UTF-8 编码的二进制文件。如果你想枚举一个二进制文件,它只是一个字节的集合,你需要指定如何。
String.graphemes/1
- 这将为您提供一个字符串列表,其中每个字符串都包含一个单独的 Unicode 字素。如果您想要每个“字符”,这可能最接近您的意思。
iex> String.graphemes("José1 José2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "é", "2"]
String.codepoints/1
- 这将为您提供按 Unicode 代码点细分的字符串列表。请注意,Unicode 代码点不一定转换为人类可读的字符。
iex> String.codepoints("José1 José2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "́", "2"]
您可以看到第一个和第二个 é
graphemes 在 unicode 代码点方面的表示不同。第一个是 LATIN SMALL LETTER E WITH ACUTE (U+00E9)
,而第二个是 LATIN SMALL LETTER E (U+0065)
,然后是 COMBINING ACUTE ACCENT (U+0301)
。
这就是为什么你不能简单地枚举一个字符串,因为在处理 Unicode 时,你必须指定你是否对字素、代码点或其他东西感兴趣。
String.to_charlist/1
- 为您提供字符串的数字 Unicode 代码点列表。这可用于与使用此格式的 Erlang 库进行交互。
iex> String.to_charlist("José1 José2")
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
:binary.bin_to_list/1
- 如果你只想枚举字节。
iex> :binary.bin_to_list("José1 José2")
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
一旦你有了一个列表,你就可以使用理解或 Enum
模块中的任何函数来枚举它:
iex> for c <- String.graphemes("José1 José2"), into: "", do: c <> c
"JJoosséé11 JJoosséé22"
iex> "José1 José2" |> String.graphemes() |> Enum.join("|")
"J|o|s|é|1| |J|o|s|é|2"
也可以使用 comprehensions 和位串生成器来枚举字节和代码点(但不是字素)。
相当于:binary.bin_to_list/1
:
iex> for <<byte <- "José1 José2">>, do: byte
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
相当于String.to_charlist/1
,通过指定二进制的type为utf8
:
iex> for <<cp::utf8 <- "José1 José2">>, do: cp
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
相当于String.codepoints/1
,通过指定二进制文件的类型为utf8
,并将生成的代码点转换回UTF-8二进制文件:
iex> for <<cp::utf8 <- "José1 José2">>, do: <<cp::utf8>>
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "́", "2"]
P.S。要进一步阅读有关字符编码的信息,这篇 2003 年的博客 post 很棒:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).
在 Elixir 中,如果我有一个字符串,例如 "José1 José2"
,我该如何枚举它?如果我尝试使用 Enum
或 for
理解,我会收到以下错误:
** (Protocol.UndefinedError) protocol Enumerable not implemented for "José1 José2" of type BitString
Elixir 中的字符串是 UTF-8 编码的二进制文件。如果你想枚举一个二进制文件,它只是一个字节的集合,你需要指定如何。
String.graphemes/1
- 这将为您提供一个字符串列表,其中每个字符串都包含一个单独的 Unicode 字素。如果您想要每个“字符”,这可能最接近您的意思。
iex> String.graphemes("José1 José2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "é", "2"]
String.codepoints/1
- 这将为您提供按 Unicode 代码点细分的字符串列表。请注意,Unicode 代码点不一定转换为人类可读的字符。
iex> String.codepoints("José1 José2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "́", "2"]
您可以看到第一个和第二个 é
graphemes 在 unicode 代码点方面的表示不同。第一个是 LATIN SMALL LETTER E WITH ACUTE (U+00E9)
,而第二个是 LATIN SMALL LETTER E (U+0065)
,然后是 COMBINING ACUTE ACCENT (U+0301)
。
这就是为什么你不能简单地枚举一个字符串,因为在处理 Unicode 时,你必须指定你是否对字素、代码点或其他东西感兴趣。
String.to_charlist/1
- 为您提供字符串的数字 Unicode 代码点列表。这可用于与使用此格式的 Erlang 库进行交互。
iex> String.to_charlist("José1 José2")
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
:binary.bin_to_list/1
- 如果你只想枚举字节。
iex> :binary.bin_to_list("José1 José2")
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
一旦你有了一个列表,你就可以使用理解或 Enum
模块中的任何函数来枚举它:
iex> for c <- String.graphemes("José1 José2"), into: "", do: c <> c
"JJoosséé11 JJoosséé22"
iex> "José1 José2" |> String.graphemes() |> Enum.join("|")
"J|o|s|é|1| |J|o|s|é|2"
也可以使用 comprehensions 和位串生成器来枚举字节和代码点(但不是字素)。
相当于:binary.bin_to_list/1
:
iex> for <<byte <- "José1 José2">>, do: byte
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
相当于String.to_charlist/1
,通过指定二进制的type为utf8
:
iex> for <<cp::utf8 <- "José1 José2">>, do: cp
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
相当于String.codepoints/1
,通过指定二进制文件的类型为utf8
,并将生成的代码点转换回UTF-8二进制文件:
iex> for <<cp::utf8 <- "José1 José2">>, do: <<cp::utf8>>
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "́", "2"]
P.S。要进一步阅读有关字符编码的信息,这篇 2003 年的博客 post 很棒:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).