以下是正则表达式中具有特殊含义的字符列表。
是特殊字符,匹配除换行符外的任意单个字符。 通过拼接,我们可以构造 ‘a.b’ 这样的正则,匹配以 ‘a’ 开头、‘b’ 结尾的任意三个字符的字符串。
本身不是结构,而是后缀运算符,表示尽可能多次重复匹配前面的正则表达式。因此,‘o*’ 匹配任意数量的 ‘o’(包括零个)。
‘*’ 总是作用于**尽可能小**的前导表达式。因此,‘fo*’ 重复的是 ‘o’,而非 ‘fo’。它匹配 ‘f’、‘fo’、‘foo’ 等。
匹配器处理 ‘*’ 结构时,会先立即匹配尽可能多的重复次数,再继续匹配模式剩余部分。如果失败,则发生回溯,丢弃部分 ‘*’ 修饰结构的匹配,尝试让后续模式能够匹配。例如,用 ‘ca*ar’ 匹配字符串 ‘caaar’ 时,‘a*’ 首先尝试匹配全部三个 ‘a’;但后续模式是 ‘ar’,剩余字符只有 ‘r’,因此匹配失败。下一种可能是 ‘a*’ 只匹配两个 ‘a’,此时正则剩余部分成功匹配。
是后缀运算符,与 ‘*’ 类似,但要求前导表达式至少匹配一次。例如,‘ca+r’ 匹配 ‘car’ 和 ‘caaaar’,但不匹配 ‘cr’,而 ‘ca*r’ 可以匹配这三个字符串。
是后缀运算符,与 ‘*’ 类似,但前导表达式只能匹配零次或一次。例如,‘ca?r’ 只匹配 ‘car’ 或 ‘cr’。
是 ‘*’、‘+’、‘?’ 的 非贪婪(non-greedy) 变体。前者匹配尽可能长的子串(在保证整体匹配的前提下),而非贪婪变体则匹配尽可能短的子串。
例如,正则 ‘c[ad]*a’ 作用于字符串 ‘cdaaada’ 时匹配整个字符串;而正则 ‘c[ad]*?a’ 作用于同一字符串时,只匹配 ‘cda’。
是 括号表达式(bracket expression) (又称 字符选择集(character alternative)),以 ‘[’ 开头、‘]’ 结束。最简单的情况下,括号内的字符即为该表达式可匹配的内容。
因此,‘[ad]’ 匹配一个 ‘a’ 或一个 ‘d’,‘[ad]*’ 匹配仅由 ‘a’ 和 ‘d’ 组成的任意字符串(包括空串)。由此 ‘c[ad]*r’ 匹配 ‘cr’、‘car’、‘cdr’、‘caddaar’ 等。
你也可以在括号表达式中使用字符范围,写法为起始字符、‘-’、结束字符。例如,‘[a-z]’ 匹配任意小写 ASCII 字母。范围可以与单个字符混合使用,如 ‘[a-z$%.]’ 匹配小写 ASCII 字母或 ‘$’、‘%’、句点。但应避免一个范围的结束字符作为另一个范围的起始,例如 ‘[a-m-z]’。
括号表达式中还可以使用命名字符类(see 字符类)。例如,‘[[:ascii:]]’ 匹配任意 ASCII 字符。使用字符类等价于列出类中所有字符,但后者通常不现实。字符类不应作为范围的上下界。
常见的正则特殊字符在括号表达式内部不再特殊。另一组字符变为特殊:‘]’、‘-’、‘^’。 要在括号表达式中包含 ‘]’,将其放在最开头。要包含 ‘^’,放在除开头外的任意位置。要包含 ‘-’,放在末尾。因此,‘[]^-]’ 匹配这三个特殊字符。你不能用 ‘\’ 转义这三个字符,因为 ‘\’ 在此处不特殊。
以下范围相关行为是 Emacs 特有的,POSIX 允许但不强制,其他程序可能不同:
case-fold-search 非 nil,则 ‘[a-z]’ 同时也匹配大写字母。
部分方括号表达式虽在 Emacs 中语义明确,但并非最佳风格,包括:
‘[^’ 开始一个 取反方括号表达式(complemented bracket expression),或称 取反字符备选(complemented character alternative)。它匹配除指定字符外的任意字符。因此,‘[^a-z0-9A-Z]’ 匹配 除 ASCII 字母与数字外的所有字符。
‘^’ 仅在作为方括号表达式首字符时具有特殊含义。‘^’ 之后的字符按首字符处理(即 ‘-’ 与 ‘]’ 在此处无特殊含义)。
取反方括号表达式可匹配换行符,除非换行符被列入排除字符。这与 grep 等程序中正则表达式的处理方式不同。
可在其中指定命名字符类,用法与普通方括号表达式一致。例如,‘[^[:ascii:]]’ 匹配任意非 ASCII 字符。See 字符类。
匹配缓冲区时,‘^’ 匹配空字符串,但仅在被匹配文本的行首(或缓冲区可访问部分的起始)匹配,否则不匹配任何内容。因此,‘^foo’ 匹配出现在行首的 ‘foo’。
匹配字符串而非缓冲区时,‘^’ 匹配字符串起始或换行符之后的位置。
出于历史兼容,‘^’ 仅在正则表达式开头,或在 ‘\(’、‘\(?:’、‘\|’ 之后具有特殊含义。尽管 ‘^’ 在其他场景为普通字符,仍建议统一使用 ‘\^’ 转义。
用法与 ‘^’ 类似,但仅匹配行尾(或缓冲区可访问部分的末尾)。因此,‘x+$’ 匹配行尾一个或多个连续的 ‘x’。
匹配字符串而非缓冲区时,‘$’ 匹配字符串末尾或换行符之前的位置。
出于历史兼容,‘$’ 仅在正则表达式末尾,或在 ‘\)’、‘\|’ 之前具有特殊含义。尽管 ‘$’ 在其他场景为普通字符,仍建议统一使用 ‘\$’ 转义。
具有两种作用:转义特殊字符(包括 ‘\’ 自身),以及引入额外的特殊结构。
由于 ‘\’ 可转义特殊字符,‘\$’ 是仅匹配 ‘$’ 的正则表达式,‘\[’ 仅匹配 ‘[’,依此类推。
注意 ‘\’ 在 Lisp 字符串读取语法中同样具有特殊含义(see 字符串类型),需使用 ‘\’ 转义。例如,匹配 ‘\’ 字符的正则表达式为 ‘\\’。若要编写包含 ‘\\’ 的 Lisp 字符串,Lisp 语法要求对每个 ‘\’ 再用一个 ‘\’ 转义。因此,匹配 ‘\’ 的正则表达式对应的 Lisp 读取语法为 "\\\\"。
出于历史兼容,重复运算符若出现在正则表达式开头,或在 ‘^’、‘\`’、‘\(’、‘\(?:’、‘\|’ 之后,将被视为普通字符。例如,‘*foo’ 被当作 ‘\*foo’,‘two\|^\{2\}’ 被当作 ‘two\|^{2}’。依赖此行为并非良好实践;无论重复运算符出现在何处,均应使用正确的反斜杠转义。
由于 ‘\’ 在方括号表达式内无特殊含义,它无法取消 ‘-’、‘^’ 或 ‘]’ 的特殊含义。当这些字符无特殊含义时不应转义,否则不会提升可读性,因为反斜杠在这些字符 具有 特殊含义时可合法出现在其前面,例如 ‘[^\]’(Lisp 字符串写作 "[^\\]")匹配除反斜杠外的任意单个字符。
实际使用中,正则表达式中出现的多数 ‘]’ 都会闭合方括号表达式,因此具有特殊含义。但在某些场景下,正则表达式需要匹配包含字面量 ‘[’ 与 ‘]’ 的复杂模式。此时可能需要从头仔细解析正则表达式,以判断哪些方括号构成方括号表达式。例如,‘[^][]]’ 由取反方括号表达式 ‘[^][]’(匹配除方括号外的任意单个字符)与一个字面量 ‘]’ 组成。
精确规则为:正则表达式起始处 ‘[’ 为特殊字符,‘]’ 为普通字符,直至遇到第一个未转义的 ‘[’,此后进入方括号表达式环境;‘[’ 不再特殊(开启字符类时除外),而 ‘]’ 变为特殊字符,除非紧跟在特殊的 ‘[’ 或 ‘[^’ 之后。此状态持续至下一个不结束字符类的特殊 ‘]’,方括号表达式结束并恢复普通正则语法:未转义的 ‘[’ 重新变为特殊字符,‘]’ 恢复为普通字符。