【问题标题】:find a match and replace next line in perl在 perl 中找到匹配项并替换下一行
【发布时间】:2014-03-13 13:05:24
【问题描述】:

我正在编写 perl 脚本,需要一些帮助。要求是,我必须找到一个标签,一旦找到标签,我必须替换紧跟标签的一行中的单词。例如,如果标签是 ABC:

ABC:
string to be replaced 
some other lines
ABC: 
string to be replaced
some other lines
ABC: 
string to be replaced

我想编写一个脚本来匹配标签 (ABC),一旦找到标签,就在紧跟标签的下一行替换一个单词。

这是我的尝试:

open(my $fh, "<", "file1.txt") or die "cannot open file:$!";

while (my $line = <$fh>)) 
{
    next if ($line =~ /ABC/) {

    $line =~ s/original_string/replaced_string/;
  }
  else {
    $msg = "pattern not found \n ";
    print "$msg";
  }
}

这是正确的..?任何帮助将不胜感激。

【问题讨论】:

  • 告诉我们您的期望和所见。
  • 这是作业吗?如果是这样,请返回并再次阅读您的笔记。
  • 找到匹配后无法下一行。看来我的下一个陈述是不正确的。任何想法如何启用这个..?
  • 您需要更具体。我们不会阅读您的源代码,直到您表明您已经付出了一些努力进行调试。乍一看,您似乎需要在下一个 if 之后获取下一行。

标签: perl


【解决方案1】:

以下单线将满足您的需求:

perl -pe '++$x and next if /ABC:/; $x-- and s/old/new/ if $x' inFile > outFile

如果找到标签,代码会设置一个标志并获取下一行。如果设置了标志,则取消设置并执行替换。

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    您正在循环中执行此操作:

     next if ($line =~ /ABC/);
    

    因此,您正在读取文件,如果一行在该行的任何位置包含ABC,则跳过该行。但是,对于每隔一行,您都进行替换。最后,您将替换所有其他行上的字符串并将其打印出来,而不是打印出标签。

    这就是你所说的:

    • 我必须 阅读文件,直到我 找到 标签
    • 一旦找到标签
    • 我必须 阅读下一行并 替换紧跟标签的一行中的单词。

    所以:

    • 您想逐行读取文件。
      • 如果一行与标签匹配
        • 阅读下一行
        • 替换行上的文字
      • 打印出该行

    遵循这些指示:

    use strict;
    use warnings;                   # Hope you're using strict and warnings
    use autodie;                    # Program automatically dies on failed opens. No need to check
    use feature qw(say);            # Allows you to use say instead of print
    
    
    open my $fh, "<", "file1.txt";  # Removed parentheses. It's the latest style
    
    while (my $line = <$fh>) {
        chomp $line;               # Always do a chomp after a read.
        if ( $line eq "ABC:" ) {   # Use 'eq' to ensure an exact match for your label
            say "$line";           # Print out the current line
            $line = <$fh>          # Read the next line
            $line =~ s/old/new/;   # Replace that word
       }
       say "$line";                # Print the line
    }
    close $fh;                     # Might as well do it right
    

    请注意,当我使用say 时,我不必将\n 放在行尾。此外,通过阅读后执行chomp,我可以轻松匹配标签,而无需担心最后的\n

    这完全按照你说的应该做,但是有几个问题。第一个是当我们做$line = &lt;$fh&gt; 时,不能保证我们真的在读一行。如果文件在那里结束怎么办?

    此外,在多个位置读取文件也是一种不好的做法。它使维护程序变得更加困难。为了解决这个问题,我们将使用 flag 变量。这可以让我们知道之前的行是否是标签:

    use strict;
    use warnings;                   # Hope you're using strict and warnings
    use autodie;                    # Program automatically dies on failed opens. No need to check
    use feature qw(say);            # Allows you to use say instead of print
    
    open my $fh, "<", "file1.txt";  # Removed parentheses. It's the latest style
    
    my $tag_found = 0;             # Flag isn't set
    while (my $line = <$fh>) {
        chomp $line;               # Always do a chomp after a read.
        if ( $line eq "ABC:" ) {   # Use 'eq' to ensure an exact match for your label
            $tag_found = 1         # We found the tag!
        }
        if ( $tag_found ) {
            $line =~ s/old/new/;   # Replace that word
            $tag_found = 0;        # Reset our flag variable
        }
        say "$line";               # Print the line
    }
    close $fh;                     # Might as well do it right
    

    当然,我更愿意消除神秘的价值观。例如,标签应该是一个变量或常量。与您要搜索的字符串和要替换的字符串相同。

    你提到这是一个词,所以你的正则表达式替换应该是这样的:

    $line =~ s/\b$old_word\b/$new_word/;
    

    \b 标记单词边界。这样,如果您想用 dog 替换单词 cat,您就不会被以下语句绊倒:

    The Jeopardy category is "Say what".
    

    您不想将category 更改为dogegory

    【讨论】:

      【解决方案3】:

      您的问题是读取文件不是那样工作的。您正在逐行进行,因此当您的正则表达式测试为真时,您要更改的行还不存在。您可以尝试添加一个布尔变量来检查最后一行是否是标签。

      #!/usr/bin/perl;
      
      use strict;
      use warnings;
      
      my $found;
      my $replacement = "Hello";
      while(my $line = <>){
          if($line =~ /ABC/){
              $found = 1;
              next;
          }
          if($found){
              $line =~ s/^.*?$/$replacement/;
              $found = 0;
              print $line, "\n";
          }
      }
      

      【讨论】:

        【解决方案4】:

        或者您可以使用 File::Slurp 将整个文件读入一个字符串:

        use File::Slurp;
        $x = read_file( "file.txt" );
        $x =~ s/^(ABC:\s*$ [\n\r]{1,2}^.*?)to\sbe/$1to was/mgx;         
        print $x;
        

        使用 /m 使 ^ 和 $ 匹配嵌入的行首/行尾
        x 是允许 $ 之后的空间 - 可能有更好的方法
        产量:

        ABC:
        string to was replaced 
        some other lines
        ABC: 
        string to was replaced
        some other lines
        ABC: 
        string to was replaced
        

        【讨论】:

          【解决方案5】:

          另外,依赖perl的in-place editing

          use File::Slurp qw(read_file write_file);
          
          use strict;
          use warnings;
          
          my $file = 'fakefile1.txt';
          
          # Initialize Fake data
          write_file($file, <DATA>);
          
          # Enclosed is the actual code that you're looking for.
          # Everything else is just for testing:
          {
              local @ARGV = $file;
              local $^I = '.bac';
          
              while (<>) {
                  print;
                  if (/ABC/ && !eof) {
                      $_ = <>;
                      s/.*/replaced string/;
                      print;
                  }
              }
          
              unlink "$file$^I";
          }
          
          # Compare new file.
          print read_file($file);
          
          1;
          
          __DATA__
          ABC:
          string to be replaced 
          some other lines
          ABC: 
          string to be replaced
          some other lines
          ABC: 
          string to be replaced
          ABC: 
          

          输出

          ABC:
          replaced string
          some other lines
          ABC:
          replaced string
          some other lines
          ABC:
          replaced string
          ABC:
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-07
            • 2015-05-17
            • 2019-05-27
            • 2020-07-25
            • 2014-06-18
            • 1970-01-01
            相关资源
            最近更新 更多