在正则表达式修改重复行时复制和复制每行输入文件的最佳方法

时间:2010-02-03 21:22:58

标签: perl unix scripting

这个问题有两个部分,一个用于“单线匹配”,一个用于“多线区域匹配”另外,我有一个半工作解决方案,我想在我的解决方案中找到更强大和优雅。

  1. 单线比赛: 我想复制输入文件的每一行,使第二行是第一行的正则表达式修改: E.G。
  2. FILE.TXT

    YY BANANA, YYZ, ABC YHZ YY1
    YY APPLE , YYZ, ABC YHZ YY1
    YY ORANGE, YYZ, ABC YHZ YY1
    YZ GRAPE , YZZ, ABC YHZ YZ1
    

    BECOME:

    YY BANANA, YYZ, ABC YHZ YY1
    XY BANANA, XYZ, ABC YHZ XY1
    YY APPLE , YYZ, ABC YHZ YY1
    XY APPLE , XYZ, ABC YHZ XY1
    YY ORANGE, YYZ, ABC YHZ YY1
    XY ORANGE, XYZ, ABC YHZ XY1
    YZ GRAPE , YZZ, ABC YHZ YZ1
    XZ GRAPE , XZZ, ABC YHZ XZ1
    

    请记住,真实文件很大,而YY的例子 - > XY和YZ - > XZ 是完全正确换句话说在我的文件情况下YY,YH,YZ,Y1,Y2,Y3是 我想改为XY,XH,XZ,X1,X2,X3的符号。

    我在PERL中做了一些非常原始的事情(将创建一个链接到它 作为展示我在想什么的起点 但是我写的perl脚本并不优雅或一般,需要多个 传递文件。

    My Raw Stab .... PERL。 http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/perl-sed-awk/conditional-duplicate/

    使用我的原始刺:

    MatchDuplicate.pl  INPUT.txt YY XY > INPUT2.txt
    MatchDuplicate.pl  INPUT2.txt YH XH > INPUT3.txt
    MatchDuplicate.pl  INPUT3.txt Y1 X1 > INPUT4.txt
    MatchDuplicate.pl  INPUT4.txt Y2 X2 > INPUT5.txt
    

    使用INPUT5.txt ......

    1. 多行匹配 与上面完全相同,但输入的每个“记录”将匹配多行:
    2. FILE.TXT

      < some starting marker...startRecord:>
      data
      data
      YY data
      YY BANANA, YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YY data
      YY APPLE , YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YY data
      YY ORANGE, YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YZ data
      YZ GRAPE , YZZ, ABC YHZ YZ1
      <some ending record marker>
      

      BECOME:

      < some starting marker...startRecord:>
      data
      data
      YY data
      YY BANANA, YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      XY data
      XY BANANA, XYZ, ABC YHZ XY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YY data
      YY APPLE , YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      XY data
      XY APPLE , XYZ, ABC YHZ XY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YY data
      YY ORANGE, YYZ, ABC YHZ YY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      XY data
      XY ORANGE, XYZ, ABC YHZ XY1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      YZ data
      YZ GRAPE , YZZ, ABC YHZ YZ1
      <some ending record marker>
      < some starting marker...startRecord:>
      data
      data
      XZ data
      XZ GRAPE , XZZ, ABC YHZ XZ1
      <some ending record marker>
      

      My Raw Stab: http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/perl-sed-awk/multi-line-conditional-duplicate/

3 个答案:

答案 0 :(得分:2)

1:

while(<>) {
    say $_;
    say $_ if s/$pattern/$replacement/;
}

根据需要添加文件句柄和其他样板文件。

编辑:让我们去寻找一些更通用的东西。

首先,我们将解析出我们的命令行参数,并将我们的替换放入哈希:

$filename = shift @ARGV;
%patterns = ();
while (scalar @ARGV) {
    my $pattern = shift @ARGV;
    my $replacement = shift @ARGV;
    $patterns{$pattern} = $replacement
}

然后对于文件中的每一行,我们将逐字输出该行,然后查看它是否与我们的任何模式匹配。

while (<>) {
    say $_;
    while (my ($pattern, $replacement) = each %patterns) {
        s/$pattern/$replacement/g and say $_ if /^$pattern/;
    }
}

答案 1 :(得分:2)

这将解决您的第一个问题:

use strict;
use warnings;

die "usage..." unless @ARGV == 3;
my ($file, $src, $dst) = @ARGV;

open my $fh, '<', $file or die "Can not open $file: $!";
while (<$fh>) {
    print;
    if (/^$src\b/) {
        s/$src/$dst/g;
        print;
    }
}
close $fh;

查看链接的脚本...您可以轻松地将块注释转换为POD,以便它们有效地成为代码的联机帮助页。然后你可以使用POD::Usage 当用户做一些愚蠢的事情时获取使用信息。

答案 2 :(得分:1)

如果记录结束标记对于所有记录都相同,则可以设置$/变量,以便<FILE>一次只读取一条记录。

$\ = "<some ending record marker>\n";
while (<FILE>) {
    print $_;
    # $_ is a multi-line string so use /m modifier
    print $_ if s/$pattern/$replacement/m;
}