查看源代码 String (Elixir v1.16.2)
Elixir 中的字符串是 UTF-8 编码的二进制数据。
Elixir 中的字符串是 Unicode 字符的序列,通常用双引号括起来,例如 "hello"
和 "héllò"
。
如果字符串本身必须包含双引号,则必须使用反斜杠对其进行转义,例如:"this is a string with \"double quotes\""
。
可以使用 <>/2
运算符连接两个字符串。
iex> "hello" <> " " <> "world"
"hello world"
本模块中的函数根据 Unicode 标准,版本 15.1.0 运行。
插值
Elixir 中的字符串也支持插值。这允许您使用 #{}
语法将一些值放置在字符串中间。
iex> name = "joe"
iex> "hello #{name}"
"hello joe"
任何 Elixir 表达式在插值中都是有效的。如果给定字符串,则会按原样进行插值。如果给定任何其他值,Elixir 将尝试使用 String.Chars
协议将其转换为字符串。例如,这允许输出插值中的整数。
iex> "2 + 2 = #{2 + 2}"
"2 + 2 = 4"
如果要插值的 value 无法转换为字符串(因为它没有人类文本表示),则会引发协议错误。
转义字符
除了允许使用反斜杠转义双引号外,字符串还支持以下转义字符。
\0
- 空字节\a
- 响铃\b
- 退格\t
- 水平制表符\n
- 换行符(换行符)\v
- 垂直制表符\f
- 换页符\r
- 回车符\e
- 命令转义\s
- 空格\#
- 返回#
字符本身,跳过插值\\
- 单个反斜杠\xNN
- 由十六进制NN
表示的字节\uNNNN
- 由NNNN
表示的 Unicode 代码点\u{NNNNNN}
- 由NNNNNN
表示的 Unicode 代码点
注意,通常不建议在 Elixir 字符串中使用 \xNN
,因为引入无效的字节序列会导致字符串无效。如果必须使用十六进制表示法引入字符,最好使用 Unicode 代码点,例如 \uNNNN
。事实上,理解 Unicode 代码点在进行字符串的低级操作时至关重要,所以接下来我们将详细探讨它们。
Unicode 和代码点
为了促进跨多种语言的计算机之间有意义的通信,需要一个标准,以便一台机器上的 0 和 1 在传输到另一台机器时具有相同的含义。Unicode 标准充当我们所知的所有字符的官方登记簿:这包括来自古典和历史文本的字符、表情符号以及格式化和控制字符。
Unicode 将其所有字符组织到代码表中,每个字符都分配了一个唯一的数字索引。这个数字索引称为代码点。
在 Elixir 中,您可以在字符文字前使用 ?
来显示其代码点。
iex> ?a
97
iex> ?ł
322
请注意,大多数 Unicode 代码表都使用其十六进制 (hex) 表示法来引用代码点,例如 97
在十六进制中转换为 0061
,我们可以使用 \u
转义字符后跟其代码点号来表示 Elixir 字符串中的任何 Unicode 字符。
iex> "\u0061" === "a"
true
iex> 0x0061 = 97 = ?a
97
十六进制表示法还有助于您查找有关代码点的信息,例如 https://codepoints.net/U+0061 包含有关小写字母 a
(即代码点 97)的所有数据表。请记住,您可以通过调用 Integer.to_string/2
来获取数字的十六进制表示。
iex> Integer.to_string(?a, 16)
"61"
UTF-8 编码和编码
现在我们了解了 Unicode 标准是什么以及代码点是什么,我们终于可以谈谈编码了。代码点是 我们存储什么,而编码则处理 我们如何存储它:编码是实现。换句话说,我们需要一种机制将代码点号转换为字节,以便它们可以存储在内存中、写入磁盘等。
Elixir 使用 UTF-8 来编码其字符串,这意味着代码点被编码为一系列 8 位字节。UTF-8 是一种 可变宽度 字符编码,它使用一个到四个字节来存储每个代码点。它能够编码所有有效的 Unicode 代码点。让我们看一个例子。
iex> string = "héllo"
"héllo"
iex> String.length(string)
5
iex> byte_size(string)
6
虽然上面的字符串有 5 个字符,但它使用了 6 个字节,因为两个字节用于表示字符 é
。
音节簇
本模块还使用音节簇的概念(以下简称音节)。音节可以包含多个代码点,这些代码点可能会被读者视为单个字符。例如,“é” 可以表示为单个“带重音的 e”代码点,如上面字符串 "héllo"
中所示,也可以表示为字母“e”后跟“组合重音”(两个代码点)。
iex> string = "\u0065\u0301"
"é"
iex> byte_size(string)
3
iex> String.length(string)
1
iex> String.codepoints(string)
["e", "́"]
iex> String.graphemes(string)
["é"]
虽然它看起来与以前相同,但上面的例子由两个字符组成,但用户将其视为一个字符。
音节也可以是两个字符,它们在某些语言中被解释为一个字符。例如,一些语言可能将“ch”视为单个字符。但是,由于此信息取决于语言环境,因此本模块不考虑它。
一般来说,本模块中的函数依赖于 Unicode 标准,但不包含任何语言环境特定的行为。有关音节的更多信息,请参见 Unicode 标准附件 #29。
有关将二进制文件转换为其他编码以及 Unicode 规范化机制,请参见 Erlang 的 :unicode
模块。
字符串和二进制操作
为了根据 Unicode 标准运行,本模块中的许多函数都以线性时间运行,因为它们需要遍历整个字符串,以考虑正确的 Unicode 代码点。
例如,String.length/1
在输入增大时会花费更长时间。另一方面,Kernel.byte_size/1
始终以恒定时间运行(即与输入大小无关)。
这意味着与直接使用二进制数据的低级操作相比,使用本模块中的函数通常会带来性能成本。
Kernel.binary_part/3
- 检索二进制文件的一部分Kernel.bit_size/1
和Kernel.byte_size/1
- 与大小相关的函数Kernel.is_bitstring/1
和Kernel.is_binary/1
- 类型检查函数- 此外,
:binary
模块 中还包含许多用于处理二进制文件(字节)的函数。
二进制语法 <<>>
中也提供了一个 utf8
修饰符。它可以用于从二进制文件/字符串中匹配代码点。
iex> <<eacute::utf8>> = "é"
iex> eacute
233
您还可以通过调用 String.to_charlist/1
将字符串完全转换为整数代码点的列表,在 Elixir 中称为“字符列表”。
iex> String.to_charlist("héllo")
[104, 233, 108, 108, 111]
如果您想查看字符串的底层字节,而不是其代码点,一个常见的技巧是将空字节 <<0>>
连接到它。
iex> "héllo" <> <<0>>
<<104, 195, 169, 108, 108, 111, 0>>
或者,您可以通过向 IO.inspect/2
传递一个选项来查看字符串的二进制表示。
IO.inspect("héllo", binaries: :as_binaries)
#=> <<104, 195, 169, 108, 108, 111>>
自同步
UTF-8 编码是自同步的。这意味着,如果遇到格式错误的数据(即根据编码定义不可能存在的数据),则只需要拒绝一个代码点。
本模块依赖于此行为来忽略此类无效字符。例如,length/1
即使馈入无效代码点,也会返回正确的结果。
换句话说,本模块期望在其他地方检测到无效数据,通常是在从外部来源检索数据时。例如,从数据库读取字符串的驱动程序将负责检查编码的有效性。可以使用 String.chunk/2
将字符串分解为有效部分和无效部分。
编译二进制模式
本模块中的许多函数都使用模式。例如,String.split/3
可以根据给定的模式将字符串拆分为多个字符串。此模式可以是字符串、字符串列表或已编译的模式。
iex> String.split("foo bar", " ")
["foo", "bar"]
iex> String.split("foo bar!", [" ", "!"])
["foo", "bar", ""]
iex> pattern = :binary.compile_pattern([" ", "!"])
iex> String.split("foo bar!", pattern)
["foo", "bar", ""]
当反复执行相同的匹配时,已编译的模式很有用。但请注意,已编译的模式不能存储在模块属性中,因为模式是在运行时生成的,并且不会在编译时保留。
总结
函数
返回给定 UTF-8 string
的 position
处的音节。如果 position
大于 string
长度,则返回 nil
。
计算两个字符串之间的袋距离。
将给定字符串中的第一个字符转换为大写,其余字符根据mode
转换为小写。
将字符串拆分成具有共同特征的字符块。
返回一个以字符串编码的代码点列表。
搜索string
是否包含给定的contents
。
根据mode
将给定字符串中的所有字符转换为小写。
返回重复n
次的字符串subject
。
如果string
以给定的任何后缀结尾,则返回true
。
如果string1
在规范上等效于string2
,则返回true
。
从 UTF-8 字符串中返回第一个音节,如果字符串为空,则返回nil
。
根据扩展音节群算法返回字符串中的 Unicode 音节。
计算两个字符串之间的 Jaro 距离(相似度)。
从 UTF-8 字符串中返回最后一个音节,如果字符串为空,则返回nil
。
返回 UTF-8 字符串中的 Unicode 音节数量。
检查string
是否与给定的正则表达式匹配。
返回表示编辑脚本的关键字列表。
返回字符串中的下一个代码点。
返回字符串中的下一个音节。
将string
中的所有字符转换为由form
标识的 Unicode 规范化形式。
返回一个新的字符串,该字符串用一个前导填充器填充,该填充器由padding
中的元素组成。
返回一个新的字符串,该字符串用一个尾随填充器填充,该填充器由padding
中的元素组成。
检查字符串是否仅包含可打印字符,最多character_limit
个字符。
返回一个新的字符串,该字符串是通过用replacement
替换subject
中pattern
的出现次数创建的。
返回一个新的字符串,该字符串是通过用replacement
(默认情况下为"�"
)替换所有无效字节创建的。
将string
中match
的所有前导出现次数替换为match
的replacement
。
如果string
中的前缀与match
匹配,则用replacement
替换前缀。
如果string
中的后缀与match
匹配,则用replacement
替换后缀。
将string
中match
的所有尾随出现次数替换为match
的replacement
。
反转给定字符串中的音节。
返回从范围开始处的偏移量到范围结束处的偏移量的子字符串。
返回从偏移量start
开始,长度为length
的子字符串。
在每个 Unicode 空格出现的位置将字符串拆分为子字符串,忽略前导和尾随空格。空格组被视为单个出现。拆分不会发生在不间断空格上。
根据模式将字符串拆分为部分。
在指定的偏移量处将字符串拆分为两个。当给定的偏移量为负数时,位置从字符串的末尾开始计数。
返回一个按需拆分字符串的可枚举对象。
如果string
以给定的任何前缀开头,则返回true
。
将字符串转换为现有原子或创建一个新的原子。
将字符串转换为字符列表。
将字符串转换为现有原子,如果原子不存在,则引发异常。
返回一个其文本表示形式为string
的浮点数。
返回一个其文本表示形式为string
的整数。
返回一个其文本表示形式为以base
为底的string
的整数。
返回一个字符串,其中已删除所有前导和尾随 Unicode 空格。
返回一个字符串,其中已删除所有前导和尾随to_trim
字符。
返回一个字符串,其中已删除所有前导 Unicode 空格。
返回一个字符串,其中已删除所有前导to_trim
字符。
返回一个字符串,其中已删除所有尾随 Unicode 空格。
返回一个字符串,其中已删除所有尾随to_trim
字符。
根据mode
将给定字符串中的所有字符转换为大写。
检查string
是否仅包含有效字符。
类型
@type codepoint() :: t()
以 UTF-8 编码的单个 Unicode 代码点。它可能是一个或多个字节。
@type grapheme() :: t()
多个代码点,读者可能会将其视为单个字符。
@type pattern() :: t() | [nonempty_binary()] | (compiled_search_pattern :: :binary.cp())
在 replace/4
和 split/3
等函数中使用的模式。
它必须是以下之一
- 一个字符串
- 一个空列表
- 一个包含非空字符串的列表
- 由
:binary.compile_pattern/1
创建的已编译搜索模式
@type t() :: binary()
UTF-8 编码的二进制文件。
类型String.t()
和binary()
对于分析工具是等效的。虽然对于阅读文档的人来说,String.t()
暗示它是一个 UTF-8 编码的二进制文件。
函数
返回给定 UTF-8 string
的 position
处的音节。如果 position
大于 string
长度,则返回 nil
。
示例
iex> String.at("elixir", 0)
"e"
iex> String.at("elixir", 1)
"l"
iex> String.at("elixir", 10)
nil
iex> String.at("elixir", -1)
"r"
iex> String.at("elixir", -10)
nil
计算两个字符串之间的袋距离。
返回一个介于 0 和 1 之间的浮点值,表示string1
和string2
之间的袋距离。
袋距离旨在成为两个字符串之间距离的有效近似值,以快速排除差异很大的字符串。
该算法概述在 Ilaria Bartolini、Paolo Ciaccia 和 Marco Patella 撰写的“使用近似距离的度量树的字符串匹配”论文中。
示例
iex> String.bag_distance("abc", "")
0.0
iex> String.bag_distance("abcd", "a")
0.25
iex> String.bag_distance("abcd", "ab")
0.5
iex> String.bag_distance("abcd", "abc")
0.75
iex> String.bag_distance("abcd", "abcd")
1.0
将给定字符串中的第一个字符转换为大写,其余字符根据mode
转换为小写。
mode
可以是:default
、:ascii
、:greek
或:turkic
。:default
模式考虑 Unicode 标准中概述的所有非条件转换。:ascii
仅将字母 A 到 Z 转换为大写。:greek
包含在希腊语中找到的上下文敏感映射。:turkic
正确处理带有无点变体的字母i
。
另请参见upcase/2
和capitalize/2
,以了解其他转换。如果您想要一个不将字符串的其余部分转换为小写的该函数的变体,请参见 Erlang 的:string.titlecase/1
。
示例
iex> String.capitalize("abcd")
"Abcd"
iex> String.capitalize("ABCD")
"Abcd"
iex> String.capitalize("fin")
"Fin"
iex> String.capitalize("olá")
"Olá"
将字符串拆分成具有共同特征的字符块。
特征可以是以下两个选项之一
:valid
- 字符串被拆分为有效和无效字符序列的块:printable
- 字符串被拆分为可打印和不可打印字符序列的块
返回一个二进制列表,其中每个二进制列表仅包含一种类型的字符。
如果给定的字符串为空,则返回一个空列表。
示例
iex> String.chunk(<<?a, ?b, ?c, 0>>, :valid)
["abc\0"]
iex> String.chunk(<<?a, ?b, ?c, 0, 0xFFFF::utf16>>, :valid)
["abc\0", <<0xFFFF::utf16>>]
iex> String.chunk(<<?a, ?b, ?c, 0, 0x0FFFF::utf8>>, :printable)
["abc", <<0, 0x0FFFF::utf8>>]
返回一个以字符串编码的代码点列表。
要以其自然整数表示形式检索代码点,请参见to_charlist/1
。有关代码点和音节的详细信息,请参见String
模块文档。
示例
iex> String.codepoints("olá")
["o", "l", "á"]
iex> String.codepoints("оптими зации")
["о", "п", "т", "и", "м", "и", " ", "з", "а", "ц", "и", "и"]
iex> String.codepoints("ἅἪῼ")
["ἅ", "Ἢ", "ῼ"]
iex> String.codepoints("\u00e9")
["é"]
iex> String.codepoints("\u0065\u0301")
["e", "́"]
搜索string
是否包含给定的contents
。
contents
可以是字符串、字符串列表或已编译的模式。如果contents
是一个列表,则此函数将搜索contents
中的任何字符串是否为string
的一部分。
在列表中搜索字符串
如果您想检查
string
是否列在contents
中,其中contents
是一个列表,请改用Enum.member?(contents, string)
。
示例
iex> String.contains?("elixir of life", "of")
true
iex> String.contains?("elixir of life", ["life", "death"])
true
iex> String.contains?("elixir of life", ["death", "mercury"])
false
参数也可以是已编译的模式
iex> pattern = :binary.compile_pattern(["life", "death"])
iex> String.contains?("elixir of life", pattern)
true
空字符串将始终匹配
iex> String.contains?("elixir of life", "")
true
iex> String.contains?("elixir of life", ["", "other"])
true
空列表将永远不会匹配
iex> String.contains?("elixir of life", [])
false
iex> String.contains?("", [])
false
请注意,此函数可以在音节边界内或跨音节边界进行匹配。例如,取音节“é”,它由字符“e”和重音组成。以下是true
iex> String.contains?(String.normalize("é", :nfd), "e")
true
但是,如果“é”由单个字符“带重音的 e”表示,那么它将返回false
iex> String.contains?(String.normalize("é", :nfc), "e")
false
根据mode
将给定字符串中的所有字符转换为小写。
mode
可以是:default
、:ascii
、:greek
或:turkic
。:default
模式考虑 Unicode 标准中概述的所有非条件转换。:ascii
仅将字母 A 到 Z 转换为小写。:greek
包含在希腊语中找到的上下文敏感映射。:turkic
正确处理带有无点变体的字母 i。
另请参阅 upcase/2
和 capitalize/2
以获取其他转换。
示例
iex> String.downcase("ABCD")
"abcd"
iex> String.downcase("AB 123 XPTO")
"ab 123 xpto"
iex> String.downcase("OLÁ")
"olá"
:ascii
模式忽略 Unicode 字符,并在您知道字符串仅包含 ASCII 字符时提供更高效的实现。
iex> String.downcase("OLÁ", :ascii)
"olÁ"
:greek
模式正确处理希腊语中对上下文敏感的西格玛。
iex> String.downcase("ΣΣ")
"σσ"
iex> String.downcase("ΣΣ", :greek)
"σς"
并且 :turkic
正确处理带点变体的字母 i。
iex> String.downcase("Iİ")
"ii̇"
iex> String.downcase("Iİ", :turkic)
"ıi"
@spec duplicate(t(), non_neg_integer()) :: t()
返回重复n
次的字符串subject
。
由编译器内联。
示例
iex> String.duplicate("abc", 0)
""
iex> String.duplicate("abc", 1)
"abc"
iex> String.duplicate("abc", 2)
"abcabc"
如果string
以给定的任何后缀结尾,则返回true
。
suffixes
可以是单个后缀或后缀列表。
示例
iex> String.ends_with?("language", "age")
true
iex> String.ends_with?("language", ["youth", "age"])
true
iex> String.ends_with?("language", ["youth", "elixir"])
false
空后缀将始终匹配。
iex> String.ends_with?("language", "")
true
iex> String.ends_with?("language", ["", "other"])
true
如果string1
在规范上等效于string2
,则返回true
。
它在比较字符串之前执行规范分解形式 (NFD) 的规范化。此函数等效于
String.normalize(string1, :nfd) == String.normalize(string2, :nfd)
如果您计划连续多次比较多个字符串,可以提前对其进行规范化,然后直接进行比较,以避免多次规范化操作。
示例
iex> String.equivalent?("abc", "abc")
true
iex> String.equivalent?("man\u0303ana", "mañana")
true
iex> String.equivalent?("abc", "ABC")
false
iex> String.equivalent?("nø", "nó")
false
从 UTF-8 字符串中返回第一个音节,如果字符串为空,则返回nil
。
示例
iex> String.first("elixir")
"e"
iex> String.first("եոգլի")
"ե"
iex> String.first("")
nil
根据扩展音节群算法返回字符串中的 Unicode 音节。
该算法概述于 Unicode 标准附录 #29,Unicode 文本分段 中。
有关代码点和字符的详细信息,请参阅 String
模块文档。
示例
iex> String.graphemes("Ńaïve")
["Ń", "a", "ï", "v", "e"]
iex> String.graphemes("\u00e9")
["é"]
iex> String.graphemes("\u0065\u0301")
["é"]
计算两个字符串之间的 Jaro 距离(相似度)。
返回一个介于 0.0
(相当于没有相似性)和 1.0
(完全匹配)之间的浮点值,表示 Jaro string1
和 string2
之间的距离。
Jaro 距离度量旨在最适合短字符串,例如人名。Elixir 本身使用此函数来提供“您是否想说?”功能。例如,当您调用模块中的函数,并且函数名有错别字时,我们会尝试根据 jaro_distance/2
得分,建议最相似的可用函数名(如果有)。
示例
iex> String.jaro_distance("Dwayne", "Duane")
0.8222222222222223
iex> String.jaro_distance("even", "odd")
0.0
iex> String.jaro_distance("same", "same")
1.0
从 UTF-8 字符串中返回最后一个音节,如果字符串为空,则返回nil
。
它遍历整个字符串以查找其最后一个字符。
示例
iex> String.last("")
nil
iex> String.last("elixir")
"r"
iex> String.last("եոգլի")
"ի"
@spec length(t()) :: non_neg_integer()
返回 UTF-8 字符串中的 Unicode 音节数量。
示例
iex> String.length("elixir")
6
iex> String.length("եոգլի")
5
检查string
是否与给定的正则表达式匹配。
示例
iex> String.match?("foo", ~r/foo/)
true
iex> String.match?("bar", ~r/foo/)
false
Elixir 还提供基于文本的匹配运算符 =~/2
和函数 Regex.match?/2
作为测试字符串与正则表达式的备选方法。
返回表示编辑脚本的关键字列表。
有关更多信息,请查看 List.myers_difference/2
。
示例
iex> string1 = "fox hops over the dog"
iex> string2 = "fox jumps over the lazy cat"
iex> String.myers_difference(string1, string2)
[eq: "fox ", del: "ho", ins: "jum", eq: "ps over the ", del: "dog", ins: "lazy cat"]
返回字符串中的下一个代码点。
结果是一个元组,包含代码点和字符串的剩余部分,或者如果字符串到达末尾则为 nil
。
与 String
模块中的其他函数一样,next_codepoint/1
使用无效的 UTF-8 的二进制文件。如果字符串以在 UTF-8 编码中无效的字节序列开头,则返回的元组的第一个元素是一个包含第一个字节的二进制文件。
示例
iex> String.next_codepoint("olá")
{"o", "lá"}
iex> invalid = "\x80\x80OK" # first two bytes are invalid in UTF-8
iex> {_, rest} = String.next_codepoint(invalid)
{<<128>>, <<128, 79, 75>>}
iex> String.next_codepoint(rest)
{<<128>>, "OK"}
与二进制模式匹配的比较
二进制模式匹配提供了一种类似的方式来分解字符串
iex> <<codepoint::utf8, rest::binary>> = "Elixir"
"Elixir"
iex> codepoint
69
iex> rest
"lixir"
虽然并不完全等效,因为 codepoint
作为整数出现,并且模式将不匹配无效的 UTF-8。
然而,二进制模式匹配更简单、更高效,因此选择最适合您的用例的选项。
返回字符串中的下一个音节。
结果是一个元组,包含字符和字符串的剩余部分,或者如果字符串到达末尾则为 nil
。
示例
iex> String.next_grapheme("olá")
{"o", "lá"}
iex> String.next_grapheme("")
nil
将string
中的所有字符转换为由form
标识的 Unicode 规范化形式。
无效的 Unicode 代码点将被跳过,剩余的字符串将被转换。如果您希望算法在无效的代码点上停止并返回,请使用 :unicode.characters_to_nfd_binary/1
、:unicode.characters_to_nfc_binary/1
、:unicode.characters_to_nfkd_binary/1
和 :unicode.characters_to_nfkc_binary/1
代替。
规范化形式 :nfkc
和 :nfkd
不应该盲目地应用于任意文本。由于它们消除了许多格式区分,因此它们将阻止与许多传统字符集的往返转换。
形式
支持的形式为
:nfd
- 规范分解形式。字符按规范等价分解,多个组合字符按特定顺序排列。:nfc
- 规范组合形式。字符被分解,然后按规范等价重新组合。:nfkd
- 兼容分解形式。字符按兼容等价分解,多个组合字符按特定顺序排列。:nfkc
- 兼容组合形式。字符被分解,然后按兼容等价重新组合。
示例
iex> String.normalize("yêṩ", :nfd)
"yêṩ"
iex> String.normalize("leña", :nfc)
"leña"
iex> String.normalize("fi", :nfkd)
"fi"
iex> String.normalize("fi", :nfkc)
"fi"
@spec pad_leading(t(), non_neg_integer(), t() | [t()]) :: t()
返回一个新的字符串,该字符串用一个前导填充器填充,该填充器由padding
中的元素组成。
将字符串列表作为 padding
传递将为每个缺失条目获取列表中的一个元素。如果列表比插入次数短,则填充将从列表开头重新开始。传递一个字符串 padding
等效于传递其中的字符列表。如果没有给出 padding
,它将默认为空格。
当 count
小于或等于 string
的长度时,将返回给定的 string
。
如果给定的 padding
包含非字符串元素,则引发 ArgumentError
。
示例
iex> String.pad_leading("abc", 5)
" abc"
iex> String.pad_leading("abc", 4, "12")
"1abc"
iex> String.pad_leading("abc", 6, "12")
"121abc"
iex> String.pad_leading("abc", 5, ["1", "23"])
"123abc"
@spec pad_trailing(t(), non_neg_integer(), t() | [t()]) :: t()
返回一个新的字符串,该字符串用一个尾随填充器填充,该填充器由padding
中的元素组成。
将字符串列表作为 padding
传递将为每个缺失条目获取列表中的一个元素。如果列表比插入次数短,则填充将从列表开头重新开始。传递一个字符串 padding
等效于传递其中的字符列表。如果没有给出 padding
,它将默认为空格。
当 count
小于或等于 string
的长度时,将返回给定的 string
。
如果给定的 padding
包含非字符串元素,则引发 ArgumentError
。
示例
iex> String.pad_trailing("abc", 5)
"abc "
iex> String.pad_trailing("abc", 4, "12")
"abc1"
iex> String.pad_trailing("abc", 6, "12")
"abc121"
iex> String.pad_trailing("abc", 5, ["1", "23"])
"abc123"
@spec printable?(t(), 0) :: true
@spec printable?(t(), pos_integer() | :infinity) :: boolean()
检查字符串是否仅包含可打印字符,最多character_limit
个字符。
采用一个可选的 character_limit
作为第二个参数。如果 character_limit
为 0
,则此函数将返回 true
。
示例
iex> String.printable?("abc")
true
iex> String.printable?("abc" <> <<0>>)
false
iex> String.printable?("abc" <> <<0>>, 2)
true
iex> String.printable?("abc" <> <<0>>, 0)
true
返回一个新的字符串,该字符串是通过用replacement
替换subject
中pattern
的出现次数创建的。
subject
始终是一个字符串。
pattern
可以是字符串、字符串列表、正则表达式或已编译的模式。
replacement
可以是字符串或函数,该函数接收匹配的模式,必须以字符串或 iodata 的形式返回替换。
默认情况下,它替换所有出现的情况,但可以通过 :global
选项控制此行为;请参阅下面的“选项”部分。
选项
:global
- (布尔值) 如果为true
,则用replacement
替换所有出现的pattern
,否则仅替换第一个出现的pattern
。默认为true
示例
iex> String.replace("a,b,c", ",", "-")
"a-b-c"
iex> String.replace("a,b,c", ",", "-", global: false)
"a-b,c"
模式也可以是字符串列表,替换也可以是接收匹配项的函数
iex> String.replace("a,b,c", ["a", "c"], fn <<char>> -> <<char + 1>> end)
"b,b,d"
当模式为正则表达式时,可以在 replacement
字符串中给出 \N
或 \g{N}
来访问正则表达式中的特定捕获。
iex> String.replace("a,b,c", ~r/,(.)/, ",\\1\\g{1}")
"a,bb,cc"
请注意,我们必须转义反斜杠转义字符(即,我们使用 \\N
而不是 \N
来转义反斜杠;\\g{N}
也是如此)。通过给出 \0
,可以在替换字符串中注入整个匹配项。
也可以给出已编译的模式
iex> pattern = :binary.compile_pattern(",")
iex> String.replace("a,b,c", pattern, "[]")
"a[]b[]c"
当提供空字符串作为 pattern
时,该函数将将其视为每个字符之间的隐式空字符串,并且字符串将被交织在一起。如果提供空字符串作为 replacement
,则将返回 subject
iex> String.replace("ELIXIR", "", ".")
".E.L.I.X.I.R."
iex> String.replace("ELIXIR", "", "")
"ELIXIR"
请注意,此函数可以在字符边界内或跨字符边界进行替换。例如,以字符“é”为例,它由字符“e”和重音符号组成。以下将仅替换字母“e”,并将重音符号移至字母“o”
iex> String.replace(String.normalize("é", :nfd), "e", "o")
"ó"
但是,如果“é”由单个字符“带重音的 e”表示,则它根本不会被替换
iex> String.replace(String.normalize("é", :nfc), "e", "o")
"é"
返回一个新的字符串,该字符串是通过用replacement
(默认情况下为"�"
)替换所有无效字节创建的。
示例
iex> String.replace_invalid("asd" <> <<0xFF::8>>)
"asd�"
iex> String.replace_invalid("nem rán bề bề")
"nem rán bề bề"
iex> String.replace_invalid("nem rán b" <> <<225, 187>> <> " bề")
"nem rán b� bề"
iex> String.replace_invalid("nem rán b" <> <<225, 187>> <> " bề", "ERROR!")
"nem rán bERROR! bề"
将string
中match
的所有前导出现次数替换为match
的replacement
。
如果不存在出现的情况,则返回未修改的字符串。
如果 match
为 ""
,则此函数将引发 ArgumentError
异常:发生这种情况是因为此函数替换 string
开头的 match
的所有出现情况,并且不可能替换 ""
的“多个”出现情况。
示例
iex> String.replace_leading("hello world", "hello ", "")
"world"
iex> String.replace_leading("hello hello world", "hello ", "")
"world"
iex> String.replace_leading("hello world", "hello ", "ola ")
"ola world"
iex> String.replace_leading("hello hello world", "hello ", "ola ")
"ola ola world"
此函数可以在字符边界之间进行替换。有关更多信息和示例,请参阅 replace/3
。
如果string
中的前缀与match
匹配,则用replacement
替换前缀。
如果不存在匹配项,则返回未修改的字符串。如果 match
为空字符串 (""
),则 replacement
仅附加到 string
。
示例
iex> String.replace_prefix("world", "hello ", "")
"world"
iex> String.replace_prefix("hello world", "hello ", "")
"world"
iex> String.replace_prefix("hello hello world", "hello ", "")
"hello world"
iex> String.replace_prefix("world", "hello ", "ola ")
"world"
iex> String.replace_prefix("hello world", "hello ", "ola ")
"ola world"
iex> String.replace_prefix("hello hello world", "hello ", "ola ")
"ola hello world"
iex> String.replace_prefix("world", "", "hello ")
"hello world"
此函数可以在字符边界之间进行替换。有关更多信息和示例,请参阅 replace/3
。
如果string
中的后缀与match
匹配,则用replacement
替换后缀。
如果不存在匹配项,则返回未修改的字符串。如果 match
为空字符串 (""
),则 replacement
仅附加到 string
。
示例
iex> String.replace_suffix("hello", " world", "")
"hello"
iex> String.replace_suffix("hello world", " world", "")
"hello"
iex> String.replace_suffix("hello world world", " world", "")
"hello world"
iex> String.replace_suffix("hello", " world", " mundo")
"hello"
iex> String.replace_suffix("hello world", " world", " mundo")
"hello mundo"
iex> String.replace_suffix("hello world world", " world", " mundo")
"hello world mundo"
iex> String.replace_suffix("hello", "", " world")
"hello world"
此函数可以在字符边界之间进行替换。有关更多信息和示例,请参阅 replace/3
。
将string
中match
的所有尾随出现次数替换为match
的replacement
。
如果不存在出现的情况,则返回未修改的字符串。
如果 match
为 ""
,则此函数会引发 ArgumentError
异常:这是因为此函数会替换 string
末尾所有出现的 match
,而无法替换 ""
的“多个”出现。
示例
iex> String.replace_trailing("hello world", " world", "")
"hello"
iex> String.replace_trailing("hello world world", " world", "")
"hello"
iex> String.replace_trailing("hello world", " world", " mundo")
"hello mundo"
iex> String.replace_trailing("hello world world", " world", " mundo")
"hello mundo mundo"
此函数可以在字符边界之间进行替换。有关更多信息和示例,请参阅 replace/3
。
反转给定字符串中的音节。
示例
iex> String.reverse("abcd")
"dcba"
iex> String.reverse("hello world")
"dlrow olleh"
iex> String.reverse("hello ∂og")
"go∂ olleh"
请记住,对同一字符串进行两次反转并不一定能得到原始字符串。
iex> "̀e"
"̀e"
iex> String.reverse("̀e")
"è"
iex> String.reverse(String.reverse("̀e"))
"è"
在第一个示例中,重音符号位于元音之前,因此被视为两个音素。但是,当你反转它一次时,你将有元音后跟重音符号,这变成一个音素。再次反转它将保留它作为一个单一的音素。
返回从范围开始处的偏移量到范围结束处的偏移量的子字符串。
如果范围的开始不是给定字符串的有效偏移量,或者范围是反向顺序,则返回 ""
。
如果范围的开始或结束为负数,则首先遍历整个字符串,以将负索引转换为正索引。
请记住,此函数使用 Unicode 音素,并将切片视为表示音素偏移量。如果你想在原始字节上拆分,请检查 Kernel.binary_part/3
或 Kernel.binary_slice/2
。
示例
iex> String.slice("elixir", 1..3)
"lix"
iex> String.slice("elixir", 1..10)
"lixir"
iex> String.slice("elixir", -4..-1)
"ixir"
iex> String.slice("elixir", -4..6)
"ixir"
iex> String.slice("elixir", -100..100)
"elixir"
对于 start > stop
的范围,你需要显式地将它们标记为递增。
iex> String.slice("elixir", 2..-1//1)
"ixir"
iex> String.slice("elixir", 1..-2//1)
"lixi"
你可以使用 ../0
作为 0..-1//1
的快捷方式,它会返回整个字符串。
iex> String.slice("elixir", ..)
"elixir"
步长可以是任何正数。例如,要获取字符串中每 2 个字符。
iex> String.slice("elixir", 0..-1//2)
"eii"
如果第一个位置在字符串结束之后或范围的最后一个位置之后,则返回空字符串。
iex> String.slice("elixir", 10..3//1)
""
iex> String.slice("a", 1..1500)
""
@spec slice(t(), integer(), non_neg_integer()) :: grapheme()
返回从偏移量start
开始,长度为length
的子字符串。
如果偏移量大于字符串长度,则返回 ""
。
请记住,此函数使用 Unicode 音素,并将切片视为表示音素偏移量。如果你想在原始字节上拆分,请检查 Kernel.binary_part/3
或 Kernel.binary_slice/3
。
示例
iex> String.slice("elixir", 1, 3)
"lix"
iex> String.slice("elixir", 1, 10)
"lixir"
iex> String.slice("elixir", 10, 3)
""
如果起始位置为负数,则会针对字符串长度进行规范化,并钳制到 0。
iex> String.slice("elixir", -4, 4)
"ixir"
iex> String.slice("elixir", -10, 3)
"eli"
如果 start 大于字符串长度,则返回空字符串。
iex> String.slice("elixir", 10, 1500)
""
在每个 Unicode 空格出现的位置将字符串拆分为子字符串,忽略前导和尾随空格。空格组被视为单个出现。拆分不会发生在不间断空格上。
示例
iex> String.split("foo bar")
["foo", "bar"]
iex> String.split("foo" <> <<194, 133>> <> "bar")
["foo", "bar"]
iex> String.split(" foo bar ")
["foo", "bar"]
iex> String.split("no\u00a0break")
["no\u00a0break"]
根据模式将字符串拆分为部分。
返回这些部分的列表。
pattern
可以是字符串、字符串列表、正则表达式或已编译的模式。
默认情况下,字符串将尽可能多地拆分为多个部分,但可以通过 :parts
选项进行控制。
只有当 :trim
选项设置为 true
时,才会从结果中删除空字符串。
当使用的模式是正则表达式时,字符串将使用 Regex.split/3
拆分。
选项
:parts
(正整数或:infinity
) - 字符串最多拆分为此选项指定的多个部分。如果为:infinity
,则字符串将拆分为所有可能的部件。默认值为:infinity
。:trim
(布尔值) - 如果为true
,则从结果列表中删除空字符串。
如果 pattern
是正则表达式,此函数还接受 Regex.split/3
接受的所有选项。
示例
使用字符串模式拆分
iex> String.split("a,b,c", ",")
["a", "b", "c"]
iex> String.split("a,b,c", ",", parts: 2)
["a", "b,c"]
iex> String.split(" a b c ", " ", trim: true)
["a", "b", "c"]
模式列表
iex> String.split("1,2 3,4", [" ", ","])
["1", "2", "3", "4"]
正则表达式
iex> String.split("a,b,c", ~r{,})
["a", "b", "c"]
iex> String.split("a,b,c", ~r{,}, parts: 2)
["a", "b,c"]
iex> String.split(" a b c ", ~r{\s}, trim: true)
["a", "b", "c"]
iex> String.split("abc", ~r{b}, include_captures: true)
["a", "b", "c"]
已编译的模式
iex> pattern = :binary.compile_pattern([" ", ","])
iex> String.split("1,2 3,4", pattern)
["1", "2", "3", "4"]
用空字符串拆分返回音素
iex> String.split("abc", "")
["", "a", "b", "c", ""]
iex> String.split("abc", "", trim: true)
["a", "b", "c"]
iex> String.split("abc", "", parts: 1)
["abc"]
iex> String.split("abc", "", parts: 3)
["", "a", "bc"]
请注意,此函数可以在音素边界内或跨音素边界进行拆分。例如,以音素“é”为例,它由字符“e”和重音符号组成。以下将字符串拆分为两个部分。
iex> String.split(String.normalize("é", :nfd), "e")
["", "́"]
但是,如果“é”由单个字符“带重音的 e”表示,则它会将字符串拆分为一个部分。
iex> String.split(String.normalize("é", :nfc), "e")
["é"]
在指定的偏移量处将字符串拆分为两个。当给定的偏移量为负数时,位置从字符串的末尾开始计数。
偏移量限制为字符串的长度。返回包含两个元素的元组。
注意:请记住,此函数在音素上拆分,因此必须线性遍历字符串。如果你想根据字节数拆分字符串或二进制文件,请使用 Kernel.binary_part/3
。
示例
iex> String.split_at("sweetelixir", 5)
{"sweet", "elixir"}
iex> String.split_at("sweetelixir", -6)
{"sweet", "elixir"}
iex> String.split_at("abc", 0)
{"", "abc"}
iex> String.split_at("abc", 1000)
{"abc", ""}
iex> String.split_at("abc", -1000)
{"", "abc"}
@spec splitter(t(), pattern(), keyword()) :: Enumerable.t()
返回一个按需拆分字符串的可枚举对象。
这与 split/3
形成对比,后者会提前拆分整个字符串。
此函数不设计为支持正则表达式。当使用正则表达式时,一次遍历字符串而不是像此函数那样分段遍历字符串通常效率更高。
选项
- :trim - 当
true
时,不会发出空模式。
示例
iex> String.splitter("1,2 3,4 5,6 7,8,...,99999", [" ", ","]) |> Enum.take(4)
["1", "2", "3", "4"]
iex> String.splitter("abcd", "") |> Enum.take(10)
["", "a", "b", "c", "d", ""]
iex> String.splitter("abcd", "", trim: true) |> Enum.take(10)
["a", "b", "c", "d"]
也可以给出已编译的模式
iex> pattern = :binary.compile_pattern([" ", ","])
iex> String.splitter("1,2 3,4 5,6 7,8,...,99999", pattern) |> Enum.take(4)
["1", "2", "3", "4"]
如果string
以给定的任何前缀开头,则返回true
。
prefix
可以是字符串、字符串列表或已编译的模式。
示例
iex> String.starts_with?("elixir", "eli")
true
iex> String.starts_with?("elixir", ["erlang", "elixir"])
true
iex> String.starts_with?("elixir", ["erlang", "ruby"])
false
空字符串将始终匹配
iex> String.starts_with?("elixir", "")
true
iex> String.starts_with?("elixir", ["", "other"])
true
空列表将永远不会匹配
iex> String.starts_with?("elixir", [])
false
iex> String.starts_with?("", [])
false
将字符串转换为现有原子或创建一个新的原子。
警告:此函数会动态创建原子,而原子不会被垃圾回收。因此,string
不应该是不受信赖的值,例如从套接字或在 Web 请求期间接收到的输入。考虑使用 to_existing_atom/1
代替。
默认情况下,原子的最大数量为 1_048_576
。此限制可以使用 VM 选项 +t
提高或降低。
最大原子大小为 255 个 Unicode 代码点。
由编译器内联。
示例
iex> String.to_atom("my_atom")
:my_atom
将字符串转换为字符列表。
具体来说,此函数接受 UTF-8 编码的二进制文件,并返回其整数代码点的列表。它类似于 codepoints/1
,不同之处在于后者返回代码点列表作为字符串。
如果你需要使用字节,请查看 :binary
模块。
示例
iex> String.to_charlist("foo")
~c"foo"
将字符串转换为现有原子,如果原子不存在,则引发异常。
最大原子大小为 255 个 Unicode 代码点。如果原子不存在,则会引发 ArgumentError
。
由编译器内联。
原子和模块
由于 Elixir 是一种编译语言,因此模块中定义的原子只有在该模块加载后才会存在,这通常发生在模块中的某个函数执行时。因此,通常建议只调用
String.to_existing_atom/1
来转换在进行函数调用以to_existing_atom/1
的模块中定义的原子。为了安全地从字符串中创建模块名称本身,建议使用
Module.safe_concat/1
。
示例
iex> _ = :my_atom
iex> String.to_existing_atom("my_atom")
:my_atom
返回一个其文本表示形式为string
的浮点数。
string
必须是浮点数的字符串表示形式,包括小数点。为了将没有小数点的字符串解析为浮点数,应使用 Float.parse/1
。否则,将引发 ArgumentError
。
由编译器内联。
示例
iex> String.to_float("2.2017764e+0")
2.2017764
iex> String.to_float("3.0")
3.0
String.to_float("3")
** (ArgumentError) argument error
返回一个其文本表示形式为string
的整数。
string
必须是整数的字符串表示形式。否则,将引发 ArgumentError
。如果你想解析可能包含格式错误整数的字符串,请使用 Integer.parse/1
。
由编译器内联。
示例
iex> String.to_integer("123")
123
传递不代表整数的字符串会导致错误。
String.to_integer("invalid data")
** (ArgumentError) argument error
返回一个其文本表示形式为以base
为底的string
的整数。
由编译器内联。
示例
iex> String.to_integer("3FF", 16)
1023
返回一个字符串,其中已删除所有前导和尾随 Unicode 空格。
示例
iex> String.trim("\n abc\n ")
"abc"
返回一个字符串,其中已删除所有前导和尾随to_trim
字符。
示例
iex> String.trim("a abc a", "a")
" abc "
返回一个字符串,其中已删除所有前导 Unicode 空格。
示例
iex> String.trim_leading("\n abc ")
"abc "
返回一个字符串,其中已删除所有前导to_trim
字符。
示例
iex> String.trim_leading("__ abc _", "_")
" abc _"
iex> String.trim_leading("1 abc", "11")
"1 abc"
返回一个字符串,其中已删除所有尾随 Unicode 空格。
示例
iex> String.trim_trailing(" abc\n ")
" abc"
返回一个字符串,其中已删除所有尾随to_trim
字符。
示例
iex> String.trim_trailing("_ abc __", "_")
"_ abc "
iex> String.trim_trailing("abc 1", "11")
"abc 1"
根据mode
将给定字符串中的所有字符转换为大写。
mode
可以是 :default
、:ascii
、:greek
或 :turkic
。:default
模式考虑 Unicode 标准中概述的所有非条件转换。 :ascii
仅将字母 a 到 z 转换为大写。 :greek
包括希腊语中发现的上下文敏感映射。 :turkic
正确处理带点和无点变体的字母 i。
示例
iex> String.upcase("abcd")
"ABCD"
iex> String.upcase("ab 123 xpto")
"AB 123 XPTO"
iex> String.upcase("olá")
"OLÁ"
:ascii
模式忽略 Unicode 字符,并在您知道字符串仅包含 ASCII 字符时提供更高效的实现。
iex> String.upcase("olá", :ascii)
"OLá"
并且 :turkic
正确处理带点变体的字母 i。
iex> String.upcase("ıi")
"II"
iex> String.upcase("ıi", :turkic)
"Iİ"
另请参阅 downcase/2
和 capitalize/2
以获取其他转换。
检查string
是否仅包含有效字符。
algorithm
可以是 :default
或 :fast_ascii
。两种算法从验证的角度来看是等效的(它们将始终生成相同的输出),但 :fast_ascii
在特定场景中可以带来显著的性能优势。
如果以下所有条件都为真,你可能需要尝试使用 :fast_ascii
算法,看看它是否能在你的特定场景中提高性能。
- 你正在 64 位平台上运行 Erlang/OTP 26 或更新版本。
- 你预计大多数字符串的长度将超过 ~64 个字节。
- 你预计大多数字符串将主要包含 ASCII 代码点。
请注意,:fast_ascii
算法不会影响正确性,你可以预期 String.valid?/2
的输出与算法无关。唯一可预期的差异是性能差异,与 :default
算法相比,预计性能将随着字符串长度大致线性提高。
示例
iex> String.valid?("a")
true
iex> String.valid?("ø")
true
iex> String.valid?(<<0xFFFF::16>>)
false
iex> String.valid?(<<0xEF, 0xB7, 0x90>>)
true
iex> String.valid?("asd" <> <<0xFFFF::16>>)
false
iex> String.valid?("a", :fast_ascii)
true
iex> String.valid?(4)
** (FunctionClauseError) no function clause matching in String.valid?/2