正则表达式并非一种单一语言。POSIX BRE、POSIX ERE 和兼容 Perl 的引擎有所重叠, 但它们的语法、匹配规则和可用功能并不相同。
POSIX BRE #
基本正则表达式是 grep 和 sed 使用的传统语法。
重要规则:
- 使用
\(和\)分组; - 使用
\{m,n\}进行计数重复; - 除非工具增加了扩展,否则
+、?、|和()都是字面字符; - 反向引用使用
\1、\2,依此类推。
BRE 具有可移植性,但由于许多元字符需要转义,其写法较为冗长。
POSIX ERE #
扩展正则表达式更接近现代正则表达式语法:
()用于分组;+表示一次或多次;?表示零次或一次;{m,n}计算重复次数;|表示交替。
grep -E 和 sed -E 使用这种形式。POSIX ERE 仍存在限制,因为它不支持惰性量词、前瞻或后顾。
兼容 Perl 的引擎 #
兼容 Perl 的正则表达式增加了 POSIX RE 不具备的功能:
*?和+?等惰性量词;- 前瞻和后顾;
(?:...)等非捕获组;- 许多引擎支持的命名捕获;
- 更丰富的字符类语法。
因此,非贪婪匹配往往要求切换引擎。POSIX BRE 和 ERE 根本没有等效运算符。
匹配行为 #
POSIX 引擎采用最左最长匹配规则。即使语法看起来相似,该规则也可能产生与 Perl 风格引擎不同的结果。
当交替和重复相互重叠时,这一点很重要,因为引擎可能选择更长的匹配, 而不是第一个成功的语法分支。
锚点也取决于引擎和模式。POSIX 的 ^ 和 $ 表示字符串的开头和结尾,
针对行的行为则取决于具体工具;PCRE 风格的引擎通常提供单独的绝对字符串锚点和多行模式。
应显式匹配输入的实际边界,而不是假定命令的默认行为。
字符类并非固定的 ASCII 简写形式。[[:alpha:]] 等 POSIX 方括号字符类遵循当前区域设置,
而 \w、大小写折叠和 Unicode 属性则因兼容 Perl 的具体实现和标志而异。
对于按字节处理的自动化任务,应设置已知区域;或者有意选择引擎的 Unicode 模式。
在含义不明确的嵌套重复上,回溯引擎可能耗费指数级时间,
例如使用 (a+)+$ 匹配较长且不匹配的输入。处理不可信数据时,应限制输入大小,
避免相互重叠的分支和嵌套量词,或使用线性时间引擎。
环视和非捕获组可以改善表达式结构,但不会使不同引擎彼此兼容。
实用转换 #
同一意图经常需要不同的语法:
- 捕获组:BRE 中为
\(...\),ERE 中为(...); - 一个或多个数字:BRE 中为
\{1,\},ERE 中为+; - 非贪婪通配符:POSIX RE 不支持。
需要可移植性时,应选定具体引擎,并使用满足任务需求的最小功能集。 转换应基于目标语言和匹配语义,而不是机械地添加或删除反斜杠。
评论
在 GitHub 上阅读或评论(发表评论需要登录)