为什么我的正则表达式在X中起作用但在Y中不起作用?

吉勒斯“别再邪恶了”

我写了一个在某些程序(grep,sed,awk,perl,python,ruby,ksh,bash,zsh,find,emacs,vi,vim,gedit等)中运行良好的正则表达式。但是,当我在其他程序(或不同的Unix变体)中使用它时,它将停止匹配。为什么?

吉勒斯“别再邪恶了”

不幸的是,由于历史原因,不同的工具使用的正则表达式语法略有不同,有时某些实现具有其他工具不支持的扩展。尽管有一个共同点,但似乎每个工具编写者都做出了不同的选择。

结果是,如果您有一个可以在一个工具中使用的正则表达式,则可能需要对其进行修改才能在另一个工具中使用。常用工具之间的主要区别是:

  • 运营商是否+?|(){}要求反斜杠;
  • 除了基础知识外.[]*^$,通常还支持哪些扩展+?|()

在此答案中,我列出了主要标准有关详细信息,请查看所用工具的文档。

Wikipedia对正则表达式引擎比较有一张表格,列出了常见实现所支持的功能。

基本正则表达式(BRE)

基本的正则表达式由POSIX标准进行了编码它是由使用的语法grepsedvi此语法提供以下功能:

  • ^并且$仅在行的开头和结尾匹配。
  • . 匹配任何字符(或除换行符以外的任何字符)。
  • […]与括号(字符集)中列出的任何一个字符匹配。如果左括号后面的第一个字符是a ^,则匹配未列出的字符。要包含],请将其放在开头之后[(或[^如果是负数之后)。如果-在两个字符之间,则表示范围;否则,表示范围。包含文字-,将其放在无法解析为范围的位置。
  • 任何^$.*\[引号前的反斜杠都将下一个字符引起来。
  • * 匹配前面的字符或子表达式0、1或更多次。
  • \(…\)是一个语法组,用于*运算符或后向引用和\DIGIT替换。
  • 后向引用\1,,\2…匹配与相应组匹配的精确文本,例如,但不\(fo*\)\(ba*\)\1匹配没有标准的方式来指代第10组及以后的组(标准含义是第一个组,后跟a )。foobaafoofoobaafo\100

以下功能也是标准功能,但某些受限制的实现中缺少这些功能:

  • \{m,n\}mn之间匹配前面的字符或子表达式nm可以省略,并且恰好表示m\{m\}
  • 在方括号内,可以使用字符类,例如[[:alpha:]]匹配任何字母。现代的实现方括号表达式)还包括排序元素[.ll.]和等价类等[=a=]

以下是常见的扩展(尤其是在GNU工具中),但并非在所有实现中都可以找到。查看所用工具的手册。

  • \|交替显示:foo\|bar匹配foobar
  • \?(简称\{0,1\})和\+(简称\{1,\})分别与前面的字符或子表达式最多匹配1次,或至少匹配1次。
  • \n匹配换行符,\t匹配制表符等。
  • \w匹配任何单词组成部分([_[:alnum:]]是本地化的缩写,但有变化),并且\W匹配任何非单词组成部分的字符。
  • \<并且\>仅在单词的开头或结尾匹配空字符串;\b匹配任何一个,\B匹配\b匹配的地方

请注意,没有\|运算符的工具没有正则表达式的全部功能。向后引用允许在数学意义上用正则表达式无法完成的一些额外操作。

扩展正则表达式(ERE)

扩展的正则表达式由POSIX标准进行了编码与BRE相比,它们的主要优点是规则性:所有标准运算符都是裸露的标点符号,标点符号之前总是用反斜杠将其引起来。它是由使用的语法awkgrep -E或者egrep,GNUsed -rbash的=~运营商。此语法提供以下功能:

  • ^并且$仅在行的开头和结尾匹配。
  • . 匹配任何字符(或除换行符以外的任何字符)。
  • […]与括号(字符集)中列出的任何一个字符匹配。带有首字母^和范围的补码的工作方式类似于BRE(请参见上文)。可以使用字符类,但某些实现中缺少字符类现代实现还支持等效类和整理元素。括号内的反斜杠在某些(但不是全部)实现中引用了下一个字符;用于\\表示可移植性的反斜杠。
  • (…)是一个语法组,用于*\DIGIT替代。
  • |交替显示:foo|bar匹配foobar
  • *+并且?与前面的字符或子表达式多次匹配:表示0或更多*,表示1或更多+,表示0或1 ?
  • 如果不是字母数字,则反斜杠会引用下一个字符。
  • {m,n}mn之间匹配前面的字符或子表达式(某些实现中缺少);nm可以省略,并且恰好表示m{m}
  • BRE中的一些常见扩展:反向引用(尤其是awk中不存在,除了可以使用的busybox实现中);特殊字符等; 词边界,词成分\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE(与Perl兼容的正则表达式)

PCRE是ERE的扩展,它最初是由Perl引入的,并且通常通过PCRE被GNUgrep -P许多现代工具和编程语言所采用请参阅Perl文档以获取带有示例的良好格式。PCRE并不支持最新版本的Perl的所有功能(例如,仅Perl支持Perl代码执行)。有关支持的功能的摘要,请参见PCRE手册ERE的主要新增功能包括:

  • (?:…)是一个非捕获组:like (…),但不计入反向引用。
  • (?=FOO)BAR(超前)匹配项BAR,但前提FOO在相同位置也有匹配项锚定匹配项而不在匹配项中包含以下文本是最有用的:foo(?=bar)匹配项,foo但仅在其后跟bar
  • (?!FOO)BAR(负向超前)匹配项BAR,但FOO在同一位置也没有匹配项例如,(?!foo)[a-z]+匹配不以foo开头的任何小写单词[a-z]+(?![0-9)匹配任何不带数字的小写单词(因此,在中foo123,它匹配fo但不匹配foo)。
  • (?<=FOO)BAR(后向)匹配项BAR,但前提是它紧随在之前FOOFOO必须具有已知长度(您不能使用重复运算符,例如*)。这对于锚定匹配项而不在匹配项中包含前面的文本是最有用的:(?<=^| )foo匹配项,foo但前提是它前面有空格或字符串的开头。
  • (?<!FOO)BAR(负向后搜索)匹配项BAR,但前提是该匹配项没有紧随其后FOOFOO必须具有已知长度(您不能使用重复运算符,例如*)。这对于锚定匹配项而不在匹配项中包含前面的文本最有用:(?<![a-z])foo匹配项,foo但前提是它前面没有小写字母。

埃马克斯

Emacs的语法介于BRE和ERE之间。除了Emacs之外,它也是-regexGNU find中的默认语法Emacs提供以下运算符:

  • ^$.[…]*+?在ERE
  • \(…\)\|\{…\}在BRE\DIGIT
  • 更多反斜杠字母序列\<\>word边界; 以及Emacs的最新版本中的更多内容,其他类似Emacs语法的引擎通常不支持。

贝壳

Shell Glob(通配符)使用与正则表达式完全不同且功能较弱的语法执行模式匹配。除外壳程序外,这些通配符还可与find -name和rsync过滤器之类的其他工具一起使用POSIX模式包括以下功能:

  • ? 匹配任何单个字符。
  • […]是常见正则表达式语法中的字符集。一些外壳程序不支持字符类。有些shell需要!而不是^否定集合。
  • *匹配任何字符序列(通常/在匹配文件路径时除外;如果/从中排除*,则**有时包括/,但请查看工具的文档)。
  • 反斜杠引用下一个字符。

Ksh提供了其他功能,使其模式与正则表达式的全部功能相匹配。运行后,这些功能也可以在bash中使用shopt -s extglobZsh的语法不同,但在之后也可以支持ksh的语法setopt ksh_glob

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我在函数中的正则表达式在 PHP 中不起作用?

为什么我的pcregrep正则表达式中的正向提前不起作用?

为什么我的正则表达式在PHP中不起作用?

为什么我的正则表达式中的可选捕获组不起作用?

为什么我的正则表达式在Java中不起作用

为什么此正则表达式在Notepad ++(Windows)中不起作用?

为什么此正则表达式在grep中不起作用?

为什么延迟匹配在此正则表达式中不起作用?

为什么使用正则表达式的str.match在Pandas中不起作用

为什么这个正则表达式在 Vim 语法高亮中不起作用?

为什么这个积极的前瞻正则表达式'string。*?(?=)'在sed中不起作用?

为什么正则表达式在空手道框架中不起作用?

为什么这个正则表达式在 powershell 中不起作用?

为什么我的正则表达式在JavaScript中不起作用?(适用于Java)

我是正则表达式的新手。为什么这场比赛在Perl中不起作用?

为什么我的有效正则表达式模式在R中不起作用

为什么我的正则表达式不起作用?[Java] [正则表达式] [空白问题]

此正则表达式为true,但在localhost中不起作用

URL中的正则表达式不起作用

python中的正则表达式不起作用

程序中的正则表达式不起作用

.htaccess中的正则表达式不起作用

Tcl中的正则表达式不起作用

+ 正则表达式在 sed 中不起作用

正则表达式在Go中不起作用

正则表达式在phonegap中不起作用

正则表达式在PHP中不起作用

__dirname在正则表达式中不起作用

问号(?)在正则表达式中不起作用