读取并修改文件

时间:2018-09-03 10:55:43

标签: regex perl aix

我正在尝试处理数据流。

首先,我将一个文本文件添加到脚本中。

文本文件如下:

pierwsza linia  koniec
druga linia lorem1 koniec lorem1 lorem1
trzecia linia lorem1 koniec lorem1
czwarta linia lorem1 koniec
piata liniakoniec
szosta linia lorem1 koniec

我要实现的是一个包含所有行的文件,但仅出现lorem1

所以预期结果应该是这样

pierwsza linia  koniec
druga linia lorem1 koniec
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec

我的脚本是这样的

#!/usr/bin/perl -pi

use strict;

my $line = $_;
my $loremcn;

while ( $line = <> ) {

    #if ( $line =~ m/lorem1/ )

    foreach ( $line =~ m/lorem1/gi ) {

        $loremcn++;

        if ( $loremcn >= 2 ) {
            $line =~ s/lorem1//gi;
        }

        print "$loremcn\n";
        print $line;

        chomp $line;
    }
}

但是结果只是文本的第一行(由于脚本开头的-pi)。

该脚本正确地统计了lorem1(7)的出现,但是由于有了/g选项,它删除了所有lorem1出现的事件(它不会留下第一个)。

最后,最后如何将整个校正后的文本打印到屏幕上?

更新

我对以下答案之一发表了重要评论:

  

在RL中,我无法按照您的方式进行操作。整个练习是找到如何使用流数据执行此操作的方法。在真实情况下,整个数据不是来自打开的文本,而是从SAP流到打印机的后台打印数据。而且该数据需要在送往打印机的途中进行纠正

4 个答案:

答案 0 :(得分:2)

#!/usr/bin/perl 
use strict;
use warnings;

# lorem counter
my $loremcn = 0;
# loop over the input file
while (my $line = <> ) {
    # if line contains lorem1 but not alorem1 or lorem12
    if ($line =~ /\blorem1\b/i) {
        # not the first time. counter > 0
        if ($loremcn) {
            # remove all lorem1 and optional leading horizontal spaces
            $line =~ s/\h*\blorem1\b//gi;   # comment for syntax color /
        # first time lorem1 is encountered (counter == 0)
        } else {
            # remove all lorem1 but the first
        while ($line =~ s/
                            (\blorem1\b.*?)     # first lorem1 in the line followed by 0 or more anycharacter
                            \blorem1\b          # subsequent lorem1
                            /$1/gix             # replace with the first group (i.e. the first lorem1
            ) { 1;}
        }
        # incement counter
        $loremcn++;
    }
    # print the modified line
    print $line;
}

输出:

pierwsza linia  koniec
druga linia lorem1 koniec  
trzecia linia koniec
czwarta linia koniec
piata liniakoniec
szosta linia koniec

用法:

perl test.pl inputfile > outputfile

答案 1 :(得分:1)

使用perl的班轮:

您可以保留所有内容,直到第一个lorem,然后在此之后删除所有lorem,即

 $perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt
  • \b-用于确定边界。
  • .*?-非贪婪匹配。将所有内容匹配到第二个lorem
  • \K-丢弃以前使用的所有字符。因此,从第二个lore删除到最后

输出

pierwsza linia  koniec
druga linia lorem1 koniec
trzecia linia  koniec
czwarta linia  koniec
piata liniakoniec
szosta linia  koniec

现在,如果要将其保存在另一个文件中,可以执行以下操作:

perl -pe "undef $/;s/^.*?\blorem1\K|\blorem1//g" lorem.txt > new_file.txt

如果您的perl版本不支持\K,则可以使用:

 perl -pe "undef $/;s/(^.*?\blorem1)|\blorem1/$1/g" lorem.txt

答案 2 :(得分:0)

不仅仅是这个吗?

my $seen;
while (<>) {
  s/\blorem1\b//g if $seen;
  $seen = 1 if /\blorem1\b/;
  print;
}

更新:好的,这比我最初想象的要复杂一些。但这似乎可以满足您的要求:

#!/usr/bin/perl

use strict;
use warnings;

my $seen;

while (<>) {
  if ($seen) {
    s/\blorem1\b//g;
  } else {
    1 while s/(?<=\blorem1\b)(.*)\blorem1\b/$1/g;
    $seen = 1 if /\blorem1\b/;
  }
  print;
}

答案 3 :(得分:-1)

使用B::Deparse这样运行代码

perl -MO=Deparse xx.pl

给出此结果

BEGIN { $^I = ""; }   # From -i

LINE: while (defined($_ = readline ARGV)) {


    use strict;
    my $line = $_;
    my $loremcn;
    while (defined($line = readline ARGV)) {
        foreach $_ ($line =~ /lorem1/gi) {
            ++$loremcn;
            if ($loremcn >= 2) {
                $line =~ s/lorem1//gi;
            }
            print "$loremcn\n";
            print $line;
            chomp $line;
        }
    }


}
continue {
    die "-p destination: $!\n" unless print $_;
}

因此,您会看到代码中有两个 while循环:您不应将命令行选项与程序文件混淆,因为结果可能不太明显

这是一种实现我想要的方式。它使用您的全局计数器$loremcn expression 全局替换,以在第一个实例之后用任何内容替换lorem1

#!/usr/bin/perl

use strict;
use warnings 'all';

@ARGV = 'file1.txt';

my $loremcn = 0;

while ( <> ) {

    s{(\blorem1\b[ \t]*)}{ $loremcn++ ? '' : $1 }ge;

    print;
}

输出

pierwsza linia  koniec
druga linia lorem1 koniec 
trzecia linia koniec 
czwarta linia koniec
piata liniakoniec
szosta linia koniec