Regex perl正则表达式,ungreedy匹配不知何故不受尊重?
为什么此正则表达式要在Regex perl正则表达式,ungreedy匹配不知何故不受尊重?,regex,perl,Regex,Perl,为什么此正则表达式要在文件.hpp中的代码前面添加许可证 perl -i -0pe 's@(.*\n)*?#ifndef@//LICENSE#ifndef@' file.hpp 与: file.hpp(带Unicode BOM的utf-8): 导致 LICENSE#ifndef NDEBUG 我不明白为什么非贪婪的(.*\n)*?匹配到行? 为什么?为了使问题更容易重现,下面是一个以字符串形式显示文件内容的测试用例: $_ = "\xef\xbb\xbf#ifndef GAGA\n#defi
文件.hpp
中的代码前面添加许可证
perl -i -0pe 's@(.*\n)*?#ifndef@//LICENSE#ifndef@' file.hpp
与:
file.hpp(带Unicode BOM的utf-8):
导致
LICENSE#ifndef NDEBUG
我不明白为什么非贪婪的(.*\n)*?
匹配到行?
为什么?为了使问题更容易重现,下面是一个以字符串形式显示文件内容的测试用例:
$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n";
s@(.*\n)*?#ifndef@//LICENSE#ifndef@;
print $_
它的输出是:
//LICENSE#ifndef NDEBUG
表示regexp与字符串的大部分匹配:“\xef\xbb\xbf\ifndef GAGA\n\define GAGA\nasd\n\ifndef”
为什么是那场比赛而不是其他比赛?首先,请注意regexp不能仅匹配“\xef\xbb\xbf\ifndef”
,因为:
- 如果括号中的组匹配0次,则没有任何内容可以匹配
部分“\xef\xbb\xbf”
- 如果括号中的组至少匹配1次,则匹配必须包括一个
“\n”
开头的长字符串“\xef\xbb\xbf”
而不是输入中稍后开始的某个较短字符串,因为regexp更喜欢在尽可能靠近输入字符串开头的地方开始匹配,并且该首选项比任何单个量词的贪婪性/非贪婪性强。如果在字符串开头找到匹配项,则regexp引擎不会继续查找。它不会找到另一个可能的匹配项,从字符串的后面开始,使非贪婪量词“更快乐”
因此,总体而言,regexp从字符串的开头开始,尝试匹配非贪婪的括号组0次,发现它不起作用(因为“\xef”
不是“#”
),尝试匹配它1次,发现不起作用(因为“#define”
不是“#ifndef”
),以此类推,直到它最终发现匹配它4次有效,然后停止。4是导致字符串开头匹配的非贪婪部分的最小重复次数
我处理UTF-8 BOM诅咒的首选策略是在做任何其他事情之前将其单独剥离
$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n";
s/^\xef\xbb\xbf//;
s@(.*\n)*?#ifndef@//LICENSE#ifndef@;
print $_
您可以将这些替换合并到一个操作中,但我喜欢简单的s/^\xef\xbb\xbf/代码>因为我可以在几乎任何一行将其放入任何脚本中最坏的情况下,它什么也不做,最多只能修复一个bug
旁注:您应该使用-0777
进行整个文件的slurping-0
单独将分隔符更改为“\0”
,这样,如果文件包含NUL,它就不会执行您想要的操作。为了使问题更容易重现,下面是一个将文件内容作为字符串的测试用例:
$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n";
s@(.*\n)*?#ifndef@//LICENSE#ifndef@;
print $_
它的输出是:
//LICENSE#ifndef NDEBUG
表示regexp与字符串的大部分匹配:“\xef\xbb\xbf\ifndef GAGA\n\define GAGA\nasd\n\ifndef”
为什么是那场比赛而不是其他比赛?首先,请注意regexp不能仅匹配“\xef\xbb\xbf\ifndef”
,因为:
- 如果括号中的组匹配0次,则没有任何内容可以匹配
“\xef\xbb\xbf”
部分
- 如果括号中的组至少匹配1次,则匹配必须包括一个
“\n”
其次,regexp匹配以开头的长字符串“\xef\xbb\xbf”
而不是输入中稍后开始的某个较短字符串,因为regexp更喜欢在尽可能靠近输入字符串开头的地方开始匹配,并且该首选项比任何单个量词的贪婪性/非贪婪性强。如果在字符串开头找到匹配项,则regexp引擎不会继续查找。它不会找到另一个可能的匹配项,从字符串的后面开始,使非贪婪量词“更快乐”
因此,总体而言,regexp从字符串的开头开始,尝试匹配非贪婪的括号组0次,发现它不起作用(因为“\xef”
不是“#”
),尝试匹配它1次,发现不起作用(因为“#define”
不是“#ifndef”
),以此类推,直到它最终发现匹配它4次有效,然后停止。4是导致字符串开头匹配的非贪婪部分的最小重复次数
我处理UTF-8 BOM诅咒的首选策略是在做任何其他事情之前将其单独剥离
$_ = "\xef\xbb\xbf#ifndef GAGA\n#define GAGA\nasd\nasd\n#ifndef NDEBUG\n";
s/^\xef\xbb\xbf//;
s@(.*\n)*?#ifndef@//LICENSE#ifndef@;
print $_
您可以将这些替换合并到一个操作中,但我喜欢简单的s/^\xef\xbb\xbf/代码>因为我可以在几乎任何一行将其放入任何脚本中最坏的情况下,它什么也不做,最多只能修复一个bug
旁注:您应该使用-0777
进行整个文件的slurping-0
单独将分隔符更改为“\0”
,这样,如果文件包含NUL,它就不会执行您想要的操作。我尝试时不会这样做。我的文件的第一行是//LICENSE#ifndef GAGA
。您确定您的文件.hpp
仍然是原始文件吗?(也就是说,您还没有使用Perl就地修改使用垃圾对其进行修改吗?)此外,您的结果缺少/
之前的许可证
。这会让你烦恼吗?这很奇怪:当file.hpp
的编码是UTF8和Unicode BOM时,就会发生这种情况。(当我这样做时,上面的内容适用)有人知道问题是什么吗?Re“-0:将文件读入ram”,这不是-0
所做的。这就是-0777
所做的,这是应该使用的。当我尝试时,它不会。我的文件的第一行是//LICENSE#ifndef GAGA
。您确定您的文件.hpp
仍然是原始文件吗?(也就是说,您还没有使用Perl就地修改使用垃圾对其进行修改?)