查看源代码 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>.)/

可能会根据您的机器、字节序、可用优化和其他因素返回 truefalse。但是,可以通过访问 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/1Regex.recompile!/1 来执行运行时版本检查,并在必要时重新编译正则表达式。

总结

函数

编译正则表达式。

编译正则表达式,并在出错时抛出 Regex.CompileError

转义字符串以在正则表达式中按字面意义匹配。

返回一个布尔值,指示是否匹配。

将给定的捕获返回为一个映射,或者如果找不到任何捕获,则返回 nil

返回正则表达式中的名称列表。

返回正则表达式选项,作为字符串或列表,具体取决于它是如何编译的。

返回正则表达式中的底层 re_pattern

如果必要,重新编译现有的正则表达式。

重新编译现有的正则表达式,并在出错时抛出 Regex.CompileError

接收一个正则表达式、一个二进制字符串和一个替换字符串,返回一个新的二进制字符串,其中所有匹配项都替换为替换字符串。

对给定字符串运行正则表达式,直到第一个匹配项。它返回一个包含所有捕获的列表,或者如果未发生匹配,则返回 nil

run/3 相同,但扫描目标多次,收集正则表达式的所有匹配项。

将正则表达式源代码作为二进制字符串返回。

根据给定的模式将给定的目标拆分为给定数量的部分。

返回底层 Regex 引擎的版本。

类型

@type t() :: %Regex{
  opts: binary() | [term()],
  re_pattern: term(),
  re_version: term(),
  source: binary()
}

函数

链接到此函数

compile(source, options \\ "")

查看源代码
@spec compile(binary(), binary() | [term()]) :: {:ok, t()} | {:error, any()}

编译正则表达式。

给定的选项可以是表示与 ~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])}
链接到此函数

compile!(source, options \\ "")

查看源代码
@spec compile!(binary(), binary() | [term()]) :: t()

编译正则表达式,并在出错时抛出 Regex.CompileError

@spec escape(String.t()) :: String.t()

转义字符串以在正则表达式中按字面意义匹配。

示例

iex> Regex.escape(".")
"\\."

iex> Regex.escape("\\what if")
"\\\\what\\ if"
@spec match?(t(), String.t()) :: boolean()

返回一个布尔值,指示是否匹配。

示例

iex> Regex.match?(~r/foo/, "foo")
true

iex> Regex.match?(~r/foo/, "bar")
false

Elixir 还提供了基于文本的匹配运算符 =~/2 和函数 String.match?/2 作为测试字符串与正则表达式和字符串的替代方案。

链接到此函数

named_captures(regex, string, options \\ [])

查看源代码
@spec named_captures(t(), String.t(), [term()]) :: map() | nil

将给定的捕获返回为一个映射,或者如果找不到任何捕获,则返回 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
@spec names(t()) :: [String.t()]

返回正则表达式中的名称列表。

示例

iex> Regex.names(~r/(?<foo>bar)/)
["foo"]
@spec opts(t()) :: String.t() | [term()]

返回正则表达式选项,作为字符串或列表,具体取决于它是如何编译的。

有关更多信息,请参见 Regex.compile/2 的文档。

示例

iex> Regex.opts(~r/foo/m)
"m"

iex> Regex.opts(Regex.compile!("foo", [:caseless]))
[:caseless]
@spec re_pattern(t()) :: term()

返回正则表达式中的底层 re_pattern

链接到此函数

recompile(regex)

查看源代码 (自 1.4.0 版本起)
@spec recompile(t()) :: {:ok, t()} | {:error, any()}

如果必要,重新编译现有的正则表达式。

这将检查存储在正则表达式中的版本,并在版本不匹配的情况下重新编译正则表达式。

链接到此函数

recompile!(regex)

查看源代码 (自 1.4.0 版本起)
@spec recompile!(t()) :: t()

重新编译现有的正则表达式,并在出错时抛出 Regex.CompileError

链接到此函数

replace(regex, string, replacement, options \\ [])

查看源代码
@spec replace(t(), String.t(), String.t() | (... -> String.t()), [term()]) ::
  String.t()

接收一个正则表达式、一个二进制字符串和一个替换字符串,返回一个新的二进制字符串,其中所有匹配项都替换为替换字符串。

替换可以是字符串,也可以是返回字符串的函数。结果字符串将用作每个匹配的替换。

当替换是字符串时,它允许使用正则表达式中的方括号访问匹配的特定捕获,并通过 \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"
链接到此函数

run(regex, string, options \\ [])

查看源代码
@spec run(t(), binary(), [term()]) :: nil | [binary()] | [{integer(), integer()}]

对给定字符串运行正则表达式,直到第一个匹配项。它返回一个包含所有捕获的列表,或者如果未发生匹配,则返回 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}]
链接到此函数

scan(regex, string, options \\ [])

查看源代码
@spec scan(t(), String.t(), [term()]) :: [[String.t()]] | [[{integer(), integer()}]]

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}]]
@spec source(t()) :: String.t()

将正则表达式源代码作为二进制字符串返回。

示例

iex> Regex.source(~r/foo/)
"foo"
链接到此函数

split(regex, string, options \\ [])

查看源代码
@spec split(t(), String.t(), [term()]) :: [String.t()]

根据给定的模式将给定的目标拆分为给定数量的部分。

选项

  • :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"]
链接到此函数

version()

查看源代码 (自 1.4.0 版本起)
@spec version() :: term()

返回底层 Regex 引擎的版本。