Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 跨多行的复杂匹配_Regex_Perl_Awk_Sed_Grep - Fatal编程技术网

Regex 跨多行的复杂匹配

Regex 跨多行的复杂匹配,regex,perl,awk,sed,grep,Regex,Perl,Awk,Sed,Grep,我一直在这里搜索,很接近,但似乎仍然不是我想要做的。请考虑下面的示例测试输入,其目的是找到跨越包含ABC打印这行的行的多行的匹配,并结束包含EFG的行也打印该行,并在其间打印行。< /P> yyabc} 000 iiabc< {efg+1} 111 yyabc} 222 p {efg+13} zzz z {efg+243} {} iii oooabc> ooo ,但包括额外的线路,不介意不在那里 yyabc} <<***** extra 000

我一直在这里搜索,很接近,但似乎仍然不是我想要做的。请考虑下面的示例测试输入,其目的是找到跨越包含ABC打印这行的行的多行的匹配,并结束包含EFG的行也打印该行,并在其间打印行。< /P>
yyabc}
000
iiabc<
    {efg+1}
111
yyabc}
222
 p  {efg+13}
zzz
   z   {efg+243} {}
iii
oooabc>
ooo
,但包括额外的线路,不介意不在那里

yyabc}   <<***** extra
000      <<***** extra
iiabc<
    {efg+1}
yyabc}
222
 p  {efg+13}
oooabc>  <<***** extra
ooo      <<***** extra
因此,预期产出为:

iiabc<
    {efg+1}
yyabc}
222
 p  {efg+13}
除了依赖pcregrep之外,我在linux中还有其他的东西,有没有一个解决方案可以产生这样的多行匹配

多谢

(.*?abc(?:(?:(?!efg|abc).)|\n)*efg.*$)
通过perl试试这个

见演示

使用缓冲区捕捉abc和第一个efg之间的部分,然后删除最后一行之前的任何行,最后打印结果并继续剩余文本

如果abc与efg位于同一行,且之前没有来自同一文本部分的abc,则不起作用,因为sed//,//从一行的模式开始工作,直到另一行的模式为止

awk非常适合此任务。如果测试输入文件名为zzz,则运行:

$ awk '/abc/{a=""} /abc/,/efg/{a=a"\n"$0} /efg/{print substr(a,2);a=""}' zzz
iiabc<
    {efg+1}
yyabc}
222
 p  {efg+13}
说明:

/abc/{a=}

每次到达包含abc的行时,将变量a设置为空字符串。我们要打印的行将在下一步添加到此变量中

/abc/,/efg/{a=a\n$0}

在以包含abc的行开始并以包含efg的行结束的每一行范围内,每一行都附加到变量a

/efg/{print substra,2;a=}

当到达范围内的最后一行时,打印a。因为a以一个额外的换行符开头,所以我们使用substr来删除它


如果没有上面的第一步,程序运行正常,但会打印额外的行。包括第一步后,它们就被消除了。

一个简单的基于阵列的awk解决方案:

awk '/abc/ {delete a;j=0;flag=1}
     flag    {a[++j]=$0}
     /efg/ && flag {for (i=1;i<=j;i++){print a[i]};flag=0}' inputfile
perl -ne '
    $b = /abc/ ? $_ : "$b$_";
    print $b if (/abc/ .. /efg/) =~ /E/
  ' file.txt
/abc/{delete a;j=0;flag=1}:当查找初始模式时,删除数组,将计数器设置为零并打开find标志

标志{a[++j]=$0}:当标志打开时存储行内容


/efg/&&flag{for i=1;i使用一个perl单行程序,对整个文件进行slurp处理:

perl -0777 -ne 'print /.*abc.*\n(?:(?!.*(?:abc|efg)).*\n)*.*efg.*\n/g' file.txt
或逐行缓冲解决方案:

awk '/abc/ {delete a;j=0;flag=1}
     flag    {a[++j]=$0}
     /efg/ && flag {for (i=1;i<=j;i++){print a[i]};flag=0}' inputfile
perl -ne '
    $b = /abc/ ? $_ : "$b$_";
    print $b if (/abc/ .. /efg/) =~ /E/
  ' file.txt
开关:

-0777:对整个文件执行Slurp操作。 -n:为输入文件中的每一行创建一个while{…}循环。 -e:告诉perl在命令行上执行代码。
这可能适用于GNU sed:

sed -n '/abc/,/efg/{/abc/{h;d};H;/efg/{g;p}}' file
通过调用-n开关在grep模式下使用sed。过滤abc和efg`之间的感兴趣行。使用保留空间HS存储包含行,然后打印出来

备选方案:

sed -n '/abc/,/efg/{/abc/h;//!H;/efg/{x;p}}' file

@dinan5m3你得到了什么?该死,stackoverflow中的这个评论是怎么得到的?谢谢。我试过了,得到了以下,$cat zzz | perl-n000e'print$&while/*?abc?:?!efg | abc.\n*efg.$/gm'Close.修改为follow,似乎给出了预期的结果,$cat zzz | perl-n000e'print$&while/*?abc?:?!efg | abc.\n*efg.*m'@dinan5m3它回答了您的问题不要忘了将其标记为正确。但是,为什么这种perl方法在与实际测试输入(文件大小为2793383645)一起使用时不起作用?但是使用sed的@NeronLeVelu解决方案,使用相同的2793383645字节测试输入,正如预期的那样工作?@dinan5m3您会得到什么错误…是由于太多的内存问题吗回溯h?谢谢。我试过了,效果很好。也试过了真实的测试输入,文件大小为2793383645,效果也很好。谢谢。是的,这也很好,并且通过使用相同的测试输入,文件大小为2793383645,确认工作正常。我喜欢这个答案,因为我能理解。谢谢大家!