在 Elixir 中枚举一个字符串

Ada*_*hip 3 string enumeration elixir

在 Elixir 中,如果我有一个字符串,例如"José1 Jose?2",我该如何枚举它?如果我尝试使用Enumfor理解,我会收到以下错误:

** (Protocol.UndefinedError) 协议 Enumerable 未为 BitString 类型的“José1 Jose?2”实现

Ada*_*hip 7

Elixir 中的字符串是 UTF-8 编码的二进制文件。如果你想枚举一个二进制,它只是一个字节的集合,你需要指定如何。

String.graphemes/1- 这将为您提供一个字符串列表,其中每个字符串包含一个单独的 Unicode 字素。如果您想要每个“字符”,这可能最接近您的意思。

iex> String.graphemes("José1 Jose?2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e?", "2"]
Run Code Online (Sandbox Code Playgroud)

String.codepoints/1- 这将为您提供按 Unicode 代码点分解的字符串列表。请注意,Unicode 代码点不一定会转换为人类可读的字符。

iex> String.codepoints("José1 Jose?2")
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "?", "2"]
Run Code Online (Sandbox Code Playgroud)

你可以看到,第一和第二é 字形在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 Jose?2")
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
Run Code Online (Sandbox Code Playgroud)

:binary.bin_to_list/1 - 如果您只想枚举字节。

iex> :binary.bin_to_list("José1 Jose?2")
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
Run Code Online (Sandbox Code Playgroud)

获得列表后,您可以使用推导式或Enum模块中的任何函数枚举它:

iex> for c <- String.graphemes("José1 Jose?2"), into: "", do: c <> c
"JJoosséé11  JJoosse?e?22"

iex> "José1 Jose?2" |> String.graphemes() |> Enum.join("|")
"J|o|s|é|1| |J|o|s|e?|2"
Run Code Online (Sandbox Code Playgroud)

也可以使用内涵与位串发电机列举字节和代码点(但不是字形)。

相当于:binary.bin_to_list/1

iex> for <<byte <- "José1 Jose?2">>, do: byte
[74, 111, 115, 195, 169, 49, 32, 74, 111, 115, 101, 204, 129, 50]
Run Code Online (Sandbox Code Playgroud)

等价于String.to_charlist/1,通过指定二进制文件的类型utf8

iex> for <<cp::utf8 <- "José1 Jose?2">>, do: cp
[74, 111, 115, 233, 49, 32, 74, 111, 115, 101, 769, 50]
Run Code Online (Sandbox Code Playgroud)

等效于String.codepoints/1,通过指定二进制文件的类型为utf8,并将生成的代码点转换回 UTF-8 二进制文件:

iex> for <<cp::utf8 <- "José1 Jose?2">>, do: <<cp::utf8>>
["J", "o", "s", "é", "1", " ", "J", "o", "s", "e", "?", "2"]
Run Code Online (Sandbox Code Playgroud)

PS 要进一步阅读有关字符编码的信息,这篇 2003 年的博客文章非常棒:每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求(没有借口!)