perl正则表达式,ungreedy匹配不知何故不受尊重?

时间:2016-03-29 11:27:11

标签: regex perl

这个正则表达式在file.hpp中添加代码前面的许可证的原因是什么:

perl -i -0pe 's@(.*\n)*?#ifndef@//LICENSE#ifndef@' file.hpp

使用:

    # -0: reads the file into ram (changes file spereator)
    # -p: reads line by line
    # -e: command execution
    # -i: modifiy input directly

file.hpp(带有Unicode BOM的utf-8):

#ifndef GAGA
#define GAGA
asd
asd
#ifndef NDEBUG

结果

LICENSE#ifndef NDEBUG

我不明白为什么非贪婪的(.*\n)*?匹配直到NDEBUG线? 为什么呢?

1 个答案:

答案 0 :(得分:4)

为了使问题更容易重现,这是一个测试用例,文件内容为字符串:

$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n";
s@(.*\n)*?#ifndef@//LICENSE#ifndef@;
print $_

输出:

//LICENSE#ifndef NDEBUG

表示正则表达式匹配字符串的大部分:"\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef"

为什么匹配而不是其他?首先,请注意正则表达式只能与"\xef\xbb\xbf#ifndef"匹配,因为:

  • 如果括号内的组匹配0次,则没有任何内容可以匹配"\xef\xbb\xbf"部分。
  • 如果括号内的小组至少匹配一次,则匹配必须包含"\n"

其次,regexp匹配以"\xef\xbb\xbf"开头的长字符串,而不是输入后面的一些较短字符串,因为regexps更喜欢将匹配尽可能接近输入字符串的开头并且这种偏好比任何单个量词的贪婪/非贪婪强。如果在字符串的开头找到匹配项,则regexp引擎不会继续查找。它不会找到另一个可能的匹配,从字符串后面开始,使非贪婪量词“更快乐”。

总的来说,regexp从字符串的开头开始,尝试匹配非贪婪的括号组0次,发现它不起作用,(因为"\xef"不是{{ 1}}),尝试匹配它1次,发现它不起作用(因为"#"不是"#define"),依此类推,直到它最终发现匹配它4次为止,并停止。 4是导致在字符串开头匹配的非贪婪部分的最小重复次数。

我处理UTF-8 BOM诅咒的首选策略是在执行任何其他操作之前将其单独剥离。

"#ifndef"

你可以将这些替换合并到一个操作中,但我喜欢简单的$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n"; s/^\xef\xbb\xbf//; s@(.*\n)*?#ifndef@//LICENSE#ifndef@; print $_ ,因为我可以将它放入几乎任何脚本 - 几乎任何行! - 它最糟糕的是什么都不做,最好修复一个bug。

旁注:您应该使用s/^\xef\xbb\xbf//;进行整个文件的诽谤。仅-0777会将分隔符更改为-0,因此如果文件包含NUL,则无法执行您想要的操作。