Gil*_*il' 94 regular-expression wildcards
我写了一个正则表达式,它在某个程序(grep、sed、awk、perl、python、ruby、ksh、bash、zsh、find、emacs、vi、vim、gedit 等)中运行良好。但是当我在不同的程序(或不同的 unix 变体)中使用它时,它会停止匹配。为什么?
Gil*_*il' 132
不幸的是,由于历史原因,不同工具的正则表达式语法略有不同,有时某些实现具有其他工具不支持的扩展。虽然有一个共同点,但似乎每个工具编写者都做出了一些不同的选择。
结果是,如果您的正则表达式适用于一种工具,则可能需要对其进行修改以适用于另一种工具。常用工具之间的主要区别是:
+?|(){}需要反斜杠;.[]*^$,通常还支持哪些扩展+?|()在这个答案中,我列出了主要标准。有关详细信息,请查看您正在使用的工具的文档。
维基百科对正则表达式引擎的比较有一个表格,列出了常见实现支持的功能。
基本正则表达式由POSIX 标准编写。它是grep,sed和使用的语法vi。此语法提供以下功能:
^并且$只在一行的开头和结尾匹配。. 匹配任何字符(或除换行符以外的任何字符)。[…]匹配括号内列出的任何一个字符(字符集)。如果左括号后的第一个字符是 a ^,则匹配未列出的字符。要包含 a ],请立即将其放在开头[之后([^如果是负集,则放在之后)。如果-在两个字符之间,则表示一个范围;要包含文字-,请将其放在无法解析为范围的地方。^$.*\[下一个字符的任何引号之前的反斜杠。* 匹配前面的字符或子表达式 0、1 或多次。\(…\)是一个句法组,用于*运算符或反向引用和\DIGIT替换。\1, \2, ... 匹配与相应组匹配的确切文本,例如\(fo*\)\(ba*\)\1匹配foobaafoo但不匹配foobaafo。没有标准的方式来指代第 10 组及以后的组(标准含义\10是第一组后跟 a 0)。以下功能也是标准功能,但在某些受限实现中缺少:
\{m,n\}匹配前面的字符或子表达式m到n次;n或m可以省略,表示正好是m。\{m\}[[:alpha:]]匹配任何字母。括号表达式的现代实现)还包括整理元素(如 )[.ll.]和等价类(如[=a=].以下是常见的扩展(尤其是在 GNU 工具中),但并非在所有实现中都可以找到。检查您正在使用的工具的手册。
\|交替:foo\|bar匹配foo或bar。\?(short for \{0,1\}) 和\+(short for \{1,\}) 最多匹配前面的字符或子表达式 1 次,或分别至少匹配 1 次。\n匹配换行符,\t匹配制表符等。\w匹配任何单词组成部分(缩写,[_[:alnum:]]但在本地化方面有变化)并\W匹配任何不是单词组成部分的字符。\<并且\>分别只在单词的开头或结尾匹配空字符串;\b要么\B匹配,要么匹配\b不匹配。请注意,没有\|运算符的工具不具备正则表达式的全部功能。反向引用允许一些额外的事情,这些事情在数学意义上是正则表达式无法完成的。
扩展正则表达式由POSIX 标准编码。它们与 BRE 相比的主要优势是规律性:所有标准运算符都是裸标点字符,标点字符前的反斜杠总是引用它。它是awk, grep -Eor egrep, GNUsed -r和bash=~操作符使用的语法。此语法提供以下功能:
^并且$只在一行的开头和结尾匹配。. 匹配任何字符(或除换行符以外的任何字符)。[…]匹配括号内列出的任何一个字符(字符集)。首字母^和范围的补充与BRE 中的工作方式类似(见上文)。可以使用字符类,但在一些实现中缺少字符类。现代实现还支持等价类和整理元素。括号内的反斜杠在某些但不是所有实现中引用下一个字符;用于\\表示可移植性的反斜杠。(…)是一个句法组,用于与*或\DIGIT替换。|交替:foo|bar匹配foo或bar。*,+并?多次匹配前面的字符或子表达式:0 或更多 for *,1 或更多 for +,0 或 1 for ?。{m,n}匹配m和n次之间的前一个字符或子表达式(某些实现中缺少);n或m可以省略,表示正好是m。{m}\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\BPCRE 是 ERE 的扩展,最初由Perl引入,并被 GNUgrep -P和许多现代工具和编程语言采用,通常通过PCRE库。请参阅Perl 文档以获得带有示例的良好格式。PCRE 并非支持最新版本的 Perl 的所有功能(例如,仅 Perl 支持 Perl 代码执行)。有关支持的功能的摘要,请参阅PCRE 手册。ERE 的主要新增内容是:
(?:…)是一个非捕获组:像(…),但不计入反向引用。(?=FOO)BAR(lookahead) 匹配BAR,但前提是也有FOO从相同位置开始的匹配。这对于在匹配中不包含以下文本的情况下锚定匹配最有用:foo(?=bar)matchesfoo但仅当其后跟bar.(?!FOO)BAR(negative lookahead) 匹配BAR,但FOO在同一位置也没有匹配。例如(?!foo)[a-z]+匹配任何不以foo;开头的小写单词。[a-z]+(?![0-9)匹配任何后面没有数字的小写单词(因此在 中foo123,它匹配fo但不匹配foo)。(?<=FOO)BAR(lookbehind) 匹配BAR,但前提是它紧跟在匹配 之前FOO。FOO必须具有已知长度(您不能使用重复运算符,例如*)。这对于在匹配中不包含前面的文本的情况下锚定匹配最有用:(?<=^| )foo匹配,foo但前提是它前面有空格或字符串的开头。(?<!FOO)BAR(negative lookbehind) 匹配BAR,但前提是它前面没有立即匹配FOO。FOO必须具有已知长度(您不能使用重复运算符,例如*)。这对于在匹配中不包含前面的文本的情况下锚定匹配最有用:(?<![a-z])foo匹配,foo但前提是它前面没有小写字母。Emacs 的语法介于 BRE 和 ERE 之间。除了 Emacs 之外,它还是-regexGNU find 中的默认语法。Emacs 提供以下操作符:
^, $, ., […], *, +,?和 ERE 一样\(…\), \|, \{…\},如 BRE\DIGIT\<和\>单词边界;以及最近版本的 Emacs 中的更多内容,这些在其他具有类似 Emacs 语法的引擎中通常不受支持。Shell glob(通配符)使用与正则表达式完全不同且功能较弱的语法执行模式匹配。除了 shell 之外,这些通配符还可用于其他工具,例如find -namersync 过滤器。POSIX 模式包括以下功能:
? 匹配任何单个字符。[…]是常见正则表达式语法中的字符集。某些 shell 不支持字符类。一些 shell 需要!而不是^否定集合。*匹配任何字符序列(通常除非/匹配文件路径;如果/从 中排除*,则**有时包含/,但请检查工具的文档)。Ksh 提供了额外的功能,使其模式匹配具有正则表达式的全部功能。运行 .bash 后,这些功能也可以在 bash 中使用shopt -s extglob。Zsh 有不同的语法,但也可以支持 ksh 后的语法setopt ksh_glob。