查看源代码 Regex (Elixir v1.16.2)
为 Elixir 提供正则表达式。
Regex 基于 PCRE(Perl 兼容正则表达式)并且构建在 Erlang 的 :re
模块之上。更多信息可以在 :re
模块文档 中找到。
Elixir 中的正则表达式可以使用符号 ~r
创建(参见 sigil_r/2
)
# A simple regular expression that matches foo anywhere in the string
~r/foo/
# A regular expression with case insensitive and Unicode options
~r/foo/iu
通过符号创建的正则表达式是预编译的,并且存储在 .beam
文件中。注意,如果正在预编译 Elixir,这可能会成为问题,请参阅“预编译”部分以了解更多信息。
Regex 在内部表示为 Regex
结构体。因此,当需要匹配它们时,可以使用 %Regex{}
。请记住,所有结构体的字段都是私有的。此外,也不能保证来自同一来源的两个正则表达式是相等的,例如
~r/(?<foo>.)(?<bar>.)/ == ~r/(?<foo>.)(?<bar>.)/
可能会根据您的机器、字节序、可用优化和其他因素返回 true
或 false
。但是,可以通过访问 source
字段来检索已编译正则表达式的源代码,然后直接比较它们
~r/(?<foo>.)(?<bar>.)/.source == ~r/(?<foo>.)(?<bar>.)/.source
转义符
转义序列分为两类。
非打印字符
\a
- 报警,即 BEL 字符(十六进制 07)\e
- 转义(十六进制 1B)\f
- 换页(十六进制 0C)\n
- 换行符(十六进制 0A)\r
- 回车符(十六进制 0D)\t
- 制表符(十六进制 09)\xhh
- 十六进制代码为 hh 的字符\x{hhh..}
- 十六进制代码为 hhh.. 的字符
\u
和 \U
不受支持。其他转义序列,如用于八进制的 \ddd
,是受支持的,但建议不要使用。
通用字符类型
\d
- 任何十进制数字\D
- 任何非十进制数字的字符\h
- 任何水平空白字符\H
- 任何非水平空白字符的字符\s
- 任何空白字符\S
- 任何非空白字符的字符\v
- 任何垂直空白字符\V
- 任何非垂直空白字符的字符\w
- 任何“单词”字符\W
- 任何“非单词”字符
修饰符
创建 Regex 时可用的修饰符是
:unicode
(u) - 启用 Unicode 特定模式,如\p
,并导致像\w
、\W
、\s
这样的字符类也匹配 Unicode(参见下面“字符类”中的示例)。它期望在匹配时提供有效的 Unicode 字符串:caseless
(i) - 添加不区分大小写:dotall
(s) - 使点匹配换行符,并将换行符设置为 anycrlf;换行设置可以通过设置(*CR)
或(*LF)
或(*CRLF)
或(*ANY)
来覆盖,根据:re
文档:multiline
(m) - 使^
和$
标记每一行的开头和结尾;使用\A
和\z
来匹配字符串的开头或结尾:extended
(x) - 除非转义,否则忽略空白字符,并允许#
来分隔注释:firstline
(f) - 强制未锚定的模式在第一个换行符之前或第一个换行符处匹配,尽管匹配的文本可能会延续到换行符:ungreedy
(U) - 反转正则表达式的“贪婪性”(之前的r
选项已弃用,改为U
)
不可用的选项是
:anchored
- 不可用,请改用^
或\A
:dollar_endonly
- 不可用,请改用\z
:no_auto_capture
- 不可用,请改用?:
:newline
- 不可用,请根据:re
文档在正则表达式的开头使用(*CR)
或(*LF)
或(*CRLF)
或(*ANYCRLF)
或(*ANY)
捕获
此模块中的许多函数通过 :capture
选项处理正则表达式匹配中要捕获的内容。支持的值是
:all
- 包括完整的匹配字符串在内的所有捕获的子模式(这是默认值):first
- 只有第一个捕获的子模式,它始终是字符串的完整匹配部分;所有显式捕获的子模式都被丢弃:all_but_first
- 除第一个匹配的子模式之外的所有子模式,即所有显式捕获的子模式,但不包括字符串的完整匹配部分:none
- 根本不返回匹配的子模式:all_names
- 按子模式的名称以 **字母顺序** 捕获 Regex 中所有命名子模式匹配的列表list(binary)
- 要捕获的命名捕获列表
字符类
Regex 支持几个内置的命名字符类。它们通过将类名括在 [: :]
中,放在组内来使用。例如
iex> String.match?("123", ~r/^[[:alnum:]]+$/)
true
iex> String.match?("123 456", ~r/^[[:alnum:][:blank:]]+$/)
true
支持的类名是
- alnum - 字母和数字
- alpha - 字母
- blank - 仅空格或制表符
- cntrl - 控制字符
- digit - 十进制数字(与 \d 相同)
- graph - 打印字符,不包括空格
- lower - 小写字母
- print - 打印字符,包括空格
- punct - 打印字符,不包括字母、数字和空格
- space - 空白字符(与 PCRE 8.34 中的 \s 相同)
- upper - 大写字母
- word - “单词”字符(与 \w 相同)
- xdigit - 十六进制数字
还有一个字符类 ascii
,它错误地匹配了 Latin-1 字符,而不是 POSIX 指定的 0-127 范围。这不能在不改变其他类的行为的情况下修复,因此我们建议使用 [\\0-\x7f]
来匹配该范围。
注意,这些类的行为可能会根据 Unicode 和其他修饰符而改变
iex> String.match?("josé", ~r/^[[:lower:]]+$/)
false
iex> String.match?("josé", ~r/^[[:lower:]]+$/u)
true
iex> Regex.replace(~r/\s/, "Unicode\u00A0spaces", "-")
"Unicode spaces"
iex> Regex.replace(~r/\s/u, "Unicode\u00A0spaces", "-")
"Unicode-spaces"
预编译
使用符号构建的正则表达式是预编译的,并且存储在 .beam
文件中。预编译的正则表达式将在运行时检查,并且在不同操作系统和 OTP 版本之间可能运行速度较慢。这很少是问题,因为大多数在开发过程中共享的 Elixir 代码都是在目标上编译的(例如依赖项、归档文件和 escript),并且在生产环境中运行时,代码必须在目标上编译(通过 mix compile
或类似方法)或在主机上发布(通过 mix releases
或类似方法),并且 OTP、操作系统和体系结构与目标匹配。
如果知道正在运行的系统不同于当前系统,并且正在使用正则表达式进行多次匹配,则可以手动调用 Regex.recompile/1
或 Regex.recompile!/1
来执行运行时版本检查,并在必要时重新编译正则表达式。
总结
函数
编译正则表达式。
编译正则表达式,并在出错时抛出 Regex.CompileError
。
转义字符串以在正则表达式中按字面意义匹配。
返回一个布尔值,指示是否匹配。
将给定的捕获返回为一个映射,或者如果找不到任何捕获,则返回 nil
。
返回正则表达式中的名称列表。
返回正则表达式选项,作为字符串或列表,具体取决于它是如何编译的。
返回正则表达式中的底层 re_pattern
。
如果必要,重新编译现有的正则表达式。
重新编译现有的正则表达式,并在出错时抛出 Regex.CompileError
。
接收一个正则表达式、一个二进制字符串和一个替换字符串,返回一个新的二进制字符串,其中所有匹配项都替换为替换字符串。
对给定字符串运行正则表达式,直到第一个匹配项。它返回一个包含所有捕获的列表,或者如果未发生匹配,则返回 nil
。
与 run/3
相同,但扫描目标多次,收集正则表达式的所有匹配项。
将正则表达式源代码作为二进制字符串返回。
根据给定的模式将给定的目标拆分为给定数量的部分。
返回底层 Regex 引擎的版本。
类型
函数
编译正则表达式。
给定的选项可以是表示与 ~r
(参见 sigil_r/2
)符号相同的正则表达式选项的字符的二进制字符串,也可以是 Erlang 的 :re
模块期望的选项列表。
如果成功,它将返回 {:ok, regex}
,否则返回 {:error, reason}
。
示例
iex> Regex.compile("foo")
{:ok, ~r/foo/}
iex> Regex.compile("*foo")
{:error, {'nothing to repeat', 0}}
iex> Regex.compile("foo", "i")
{:ok, ~r/foo/i}
iex> Regex.compile("foo", [:caseless])
{:ok, Regex.compile!("foo", [:caseless])}
编译正则表达式,并在出错时抛出 Regex.CompileError
。
转义字符串以在正则表达式中按字面意义匹配。
示例
iex> Regex.escape(".")
"\\."
iex> Regex.escape("\\what if")
"\\\\what\\ if"
返回一个布尔值,指示是否匹配。
示例
iex> Regex.match?(~r/foo/, "foo")
true
iex> Regex.match?(~r/foo/, "bar")
false
Elixir 还提供了基于文本的匹配运算符 =~/2
和函数 String.match?/2
作为测试字符串与正则表达式和字符串的替代方案。
将给定的捕获返回为一个映射,或者如果找不到任何捕获,则返回 nil
。
选项
:return
- 当设置为:index
时,返回字节索引和匹配长度。默认值为:binary
。
示例
iex> Regex.named_captures(~r/c(?<foo>d)/, "abcd")
%{"foo" => "d"}
iex> Regex.named_captures(~r/a(?<foo>b)c(?<bar>d)/, "abcd")
%{"bar" => "d", "foo" => "b"}
iex> Regex.named_captures(~r/a(?<foo>b)c(?<bar>d)/, "efgh")
nil
返回正则表达式中的名称列表。
示例
iex> Regex.names(~r/(?<foo>bar)/)
["foo"]
返回正则表达式选项,作为字符串或列表,具体取决于它是如何编译的。
有关更多信息,请参见 Regex.compile/2
的文档。
示例
iex> Regex.opts(~r/foo/m)
"m"
iex> Regex.opts(Regex.compile!("foo", [:caseless]))
[:caseless]
返回正则表达式中的底层 re_pattern
。
如果必要,重新编译现有的正则表达式。
这将检查存储在正则表达式中的版本,并在版本不匹配的情况下重新编译正则表达式。
重新编译现有的正则表达式,并在出错时抛出 Regex.CompileError
。
接收一个正则表达式、一个二进制字符串和一个替换字符串,返回一个新的二进制字符串,其中所有匹配项都替换为替换字符串。
替换可以是字符串,也可以是返回字符串的函数。结果字符串将用作每个匹配的替换。
当替换是字符串时,它允许使用正则表达式中的方括号访问匹配的特定捕获,并通过 \N
或 \g{N}
在替换中访问它们,其中 N
是捕获的编号。如果使用 \0
,则插入整个匹配项。请注意,在正则表达式中,反斜杠需要转义,因此在实践中您需要使用 \\N
和 \\g{N}
。
当替换是函数时,它也允许访问特定捕获。该函数可以具有 N 元性,其中每个参数对应于一个捕获,第一个参数是整个匹配项。如果函数期望的参数比找到的捕获更多,则剩余的参数将接收 ""
。
选项
:global
- 当为false
时,只替换第一个匹配项(默认值为true
)
示例
iex> Regex.replace(~r/d/, "abc", "d")
"abc"
iex> Regex.replace(~r/b/, "abc", "d")
"adc"
iex> Regex.replace(~r/b/, "abc", "[\\0]")
"a[b]c"
iex> Regex.replace(~r/a(b|d)c/, "abcadc", "[\\1]")
"[b][d]"
iex> Regex.replace(~r/\.(\d)$/, "500.5", ".\\g{1}0")
"500.50"
iex> Regex.replace(~r/a(b|d)c/, "abcadc", fn _, x -> "[#{x}]" end)
"[b][d]"
iex> Regex.replace(~r/(\w+)@(\w+).(\w+)/, "[email protected]", fn _full, _c1, _c2, c3 -> "TLD: #{c3}" end)
"TLD: com"
iex> Regex.replace(~r/a/, "abcadc", "A", global: false)
"Abcadc"
对给定字符串运行正则表达式,直到第一个匹配项。它返回一个包含所有捕获的列表,或者如果未发生匹配,则返回 nil
。
选项
:return
- 当设置为:index
时,返回字节索引和匹配长度。默认值为:binary
。:capture
- 在结果中捕获的内容。查看Regex
的模块文档以查看可能的捕获值。:offset
- (自 v1.12.0 版本起) 指定在给定字符串中匹配的起始偏移量。默认值为零。
示例
iex> Regex.run(~r/c(d)/, "abcd")
["cd", "d"]
iex> Regex.run(~r/e/, "abcd")
nil
iex> Regex.run(~r/c(d)/, "abcd", return: :index)
[{2, 2}, {3, 1}]
与 run/3
相同,但扫描目标多次,收集正则表达式的所有匹配项。
返回一个列表列表,其中主列表中的每个条目表示一个匹配,次列表中的每个条目表示捕获的内容。
选项
:return
- 当设置为:index
时,返回字节索引和匹配长度。默认值为:binary
。:capture
- 在结果中捕获的内容。查看Regex
的模块文档以查看可能的捕获值。:offset
- (自 v1.12.0 版本起) 指定在给定字符串中匹配的起始偏移量。默认值为零。
示例
iex> Regex.scan(~r/c(d|e)/, "abcd abce")
[["cd", "d"], ["ce", "e"]]
iex> Regex.scan(~r/c(?:d|e)/, "abcd abce")
[["cd"], ["ce"]]
iex> Regex.scan(~r/e/, "abcd")
[]
iex> Regex.scan(~r/\p{Sc}/u, "$, £, and €")
[["$"], ["£"], ["€"]]
iex> Regex.scan(~r/=+/, "=ü†ƒ8===", return: :index)
[[{0, 1}], [{9, 3}]]
将正则表达式源代码作为二进制字符串返回。
示例
iex> Regex.source(~r/foo/)
"foo"
根据给定的模式将给定的目标拆分为给定数量的部分。
选项
:parts
- 当指定时,将字符串拆分为给定的部分数量。如果未指定,:parts
默认值为:infinity
,这将根据给定的模式将字符串拆分为尽可能多的部分。:trim
- 当为true
时,从结果中删除空字符串 (""
)。默认值为false
。:on
- 指定要拆分字符串的捕获,以及拆分顺序。默认值为:first
,这意味着正则表达式内部的捕获不会影响拆分过程。查看Regex
的模块文档以查看可能的捕获值。:include_captures
- 当为true
时,将正则表达式的匹配项包含在结果中。如果与:parts
选项结合使用,则匹配项不会计入最大部分数量。默认值为false
。
示例
iex> Regex.split(~r{-}, "a-b-c")
["a", "b", "c"]
iex> Regex.split(~r{-}, "a-b-c", parts: 2)
["a", "b-c"]
iex> Regex.split(~r{-}, "abc")
["abc"]
iex> Regex.split(~r{}, "abc")
["", "a", "b", "c", ""]
iex> Regex.split(~r{a(?<second>b)c}, "abc")
["", ""]
iex> Regex.split(~r{a(?<second>b)c}, "abc", on: [:second])
["a", "c"]
iex> Regex.split(~r{(x)}, "Elixir", include_captures: true)
["Eli", "x", "ir"]
iex> Regex.split(~r{a(?<second>b)c}, "abc", on: [:second], include_captures: true)
["a", "b", "c"]
@spec version() :: term()
返回底层 Regex 引擎的版本。