需要基于多行模式匹配来连接某些行

时间:2014-06-05 20:35:45

标签: regex perl

我有一个看起来像这样的文件:

2014-05-01 00:30:45,511
ZZZ|1|CE|web1||etc|etc
ZZZ|1|CE|web2||etc|etc
ZZZ|1|CE|web3|asd|SDAF
2014-05-01 00:30:45,511
ZZZ|1|CE|web1||etc|etc
ZZZ|1|CE|web2||etc|etc
ZZZ|1|CE|web3|asd|SDAF

我希望通过用管道替换换行后跟某些模式将其转换为2行。我想要:

2014-05-01 00:30:45,511|ZZZ|1|CE|web1||etc|etc|ZZZ|1|CE|web2||etc|etc|ZZZ|1|CE|web3|asd|SDAF
2014-05-01 00:30:45,511|ZZZ|1|CE|web1||etc|etc|ZZZ|1|CE|web2||etc|etc|ZZZ|1|CE|web3|asd|SDAF

我正在尝试与perl进行多行匹配:

cat file | perl -pe 's/\nZZZ/\|ZZZ/m'

但这不匹配。

我可以做perl -pe' / \ n // m'但那太多了;我需要匹配' \ nZZZ'这样只有以ZZZ开头的行才会加到前一行。

4 个答案:

答案 0 :(得分:2)

您只需使用-0777开关指示啜食模式,因为您正在使用正在尝试匹配多行的正则表达式。

完整的解决方案:

perl -0777 -pe 's/\n(?=ZZZ)/|/g' file 

说明:

切换

  • -0777:slurp files whole
  • -p:为输入文件中的每一行创建一个while(<>){...; print}循环。
  • -e:告诉perl在命令行上执行代码。

<强>代码

  • s/\n(?=ZZZ)/|/g:用|
  • 替换ZZZ后面的任何换行符

答案 1 :(得分:2)

如果你想避免啜食模式,试试这个:

perl -pe 'chomp unless eof; /\|/ and s/^/|/ or $.>1 and s/^/\n/' filename.txt
  • 如果记录分隔符包含记录分隔符,则将记录分隔符添加到行的开头。
  • 如果我们越过第一行,则开始换行。
  • 将新行保留在文件末尾。

答案 2 :(得分:0)

我建议使用Lookahead,它不会杀死你的ZZZ Part

cat file | perl -pe 's/(\n(?=ZZZ))/|/gm'

编辑:Online Demo

答案 3 :(得分:0)

这是一个非常标准的模式。看起来像这样。输入文件的路径需要作为命令行上的参数

use strict;
use warnings;

my $line;
while (<>) {
  chomp;
  if ( /^ZZZ/ ) {
    $line .= '|' . $_;
  }
  else {
    print $line, "\n" if $line;
    $line = $_;
  }
}
print $line, "\n" if $line;

<强>输出

2014-05-01 00:30:45,511|ZZZ|1|CE|web1||etc|etc|ZZZ|1|CE|web2||etc|etc|ZZZ|1|CE|web3|asd|SDAF
2014-05-01 00:30:45,511|ZZZ|1|CE|web1||etc|etc|ZZZ|1|CE|web2||etc|etc|ZZZ|1|CE|web3|asd|SDAF