【问题标题】:how to replace a line after certain keyword in perl如何在perl中的某个关键字之后替换一行
【发布时间】:2018-06-28 22:32:01
【问题描述】:

重新运行.txt

a,1
b,2
c,3
d,4

(在我的代码中,abcd 分别是 $var12...$num

我想在cell.txt 中搜索$var 并在此文件中将area(对应的下一行)替换为$num(如area : 1

cell.txt

  cell (a)  {
     area :  2
  }

  cell (b)  {
     area :  2.3
   }
  cell (c)  {
     area :  2.5
   }

  cell (d)  {
     area :  2.7
   }

Perl 代码

#!usr/bin/perl

use warnings;
use strict;

open( my $fh1, "rerun.txt" ) or die "Couldn't open file file.txt, $!";

my $word  = 0;
my $input = "area";
my $num;
my $var;
my $line;
my $a     = 0;
my $flag  = 0;
my $flag1 = 0;

while ( <$fh1> ) {

    ( $var, $num ) = split ",";    # splitting acc to comma

    open( my $fh, "cell.txt" ) or die "Couldn't open file file.txt, $!";

    while ( my $line1 = <$fh> ) {    # while in the file opened

        $line1 =~ s/^\s+//;         # removing spaces
        my @word = split " ", $line1;    # splitting acc to spcaes

        foreach $word ( @word ) {

            $word =~ s/[(,),]//g;        # excluding all brackets (,),{,}

            if ( $word eq $var ) {
                $flag = 1;
            }

            if ( $flag == 1 ) {

                if ( $word eq "area" ) {

                    $a = $.;             # saving the line number
                    system( "sed -i '$a s/.*/\t area : $num /' cell.txt" );
                    goto L1;
                }
            }
        }
    }

    L1:

    close( $fh );
}

close( $fh1 );

【问题讨论】:

  • TCL跟它有什么关系?
  • 我已经整理了你的 Perl 代码,以便我可以阅读它,但我需要这样做是可耻的。下次在这里提问时请多多努力。
  • cell.txt 中的每一项都会在 rerun.txt 中吗?
  • @trenton-trama: cell.txt 中需要更改的变量很少,不是全部。

标签: shell perl


【解决方案1】:

我依靠一些花哨的正则表达式来尝试对可能的输入进行防御并结合一些步骤。 docs on goto 建议将 last(在您的情况下为 last LABEL)作为替代方案,但我希望 OP 不会因为我呼应某些人共享的教条而感到受伤。我的版本打印到标准输出而不是更改原始文件,但应该足够接近。打印一些预期的输出会有所帮助,但希望我猜对了。

Borodin 比我早几分钟完成,我没有看到他的帖子,这在某些方面是一种更高级的方法。根据同一人的建议,我删除了对 Regexp::Common 模块的引用,虽然相关,但我同意这超出了需要。

#!/usr/bin/env perl

use Modern::Perl;

open(my $fh, '<', 'rerun.txt') or die "Could not open rerun.txt: $!";
my %new_area;
foreach (<$fh>) {
    chomp;
    my ($k, $v) = split ',';
    die "invalid rerun format" unless ($k =~ /^\w+$/ and $v =~ /^[\d.]+$/);
    $new_area{ $k } = $v;
}

open($fh, '<', 'cell.txt') or die "Could not open cell.txt: $!";
my $area_key;
while (<$fh>) {
    if ( /^\s* cell \s*\(\s*(\w+)\s*\)\s* { \s*$/x ) {
        $area_key = $1;
    }
    elsif (/^\s* } \s*$/x) {
        undef $area_key
    }
    elsif ( defined($area_key) and /\barea\b/ and
            exists $new_area{ $area_key }
    ) {
        s/(area\s*:\s*)[\d.]+/$1$new_area{$area_key}/
    }

    print;
}

输出:

  cell (a)  {
     area :  1
  }

  cell (b)  {
     area :  2
   }
  cell (c)  {
     area :  3
   }

... etc ...

【讨论】:

  • “你的尝试在我看来有点像用 Perl 编写的 BASIC 程序” 老实说,这就是你的答案在我看来的样子。首先,为什么没有use strictuse warnings 'all'
  • 鲍罗丁,你好像错过了use Modern::Perl; - metacpan.org/pod/Modern::Perl
  • 为什么我必须了解每个非核心编译模块的作用?它是不透明的,对于新手来说不是一个很好的例子。 use strictuse warnings 'all' 已足够且不言自明。一定要将Modern::Perl 用于您自己的目的,但它不适合用于生产或公共代码。
  • Regexp::Common 太过分了。 [\d.]+ 很好,除非您尝试验证输入数据,如果您需要正确处理不匹配而不是忽略它。 OP 并不暗示文件可能格式错误,因此没有任何“聪明”的意义。
  • 谢谢@mr_ron 我有非常基本的 perl 版本,我无法安装modern::perl,任何解决方案。提前致谢
【解决方案2】:

此解决方案将 rerun 数据读入哈希 %rerun,使用第一列作为键,第二列作为值。一个正则表达式模式$re 是从一组可能的键中构建并编译的

将整个cell.txt 读入$cell,以便更简单地处理多行字符串。每次出现cell (x) {,后面跟着area : 99.99,其中x%rerun的key之一,找到后面的99.99,替换成对应的哈希元素的值

找到并替换所有内容后,新的$cell 将打印到STDOUT

use strict;
use warnings 'all';
use autodie;

my %rerun = do {
    open my $fh, '<', 'rerun.txt';
    map { /[^,\s]/g } <$fh>;
};

my $cell = do {
    open my $fh, '<', 'cell.txt';
    local $/;
    <$fh>;
};

my $re = join '|', sort { length $b <=> length $a } keys %rerun;
$re = qr/$re/;

$cell =~ s/ \b cell \s* \( \s* ( $re ) \s* \) \s* \{ \s* area \s* : \s* \K [\d.]+ /$rerun{$1}/gx;

print $cell;

输出

  cell (a)  {
     area :  1
  }

  cell (b)  {
     area :  2
   }
  cell (c)  {
     area :  3
   }

  cell (d)  {
     area :  4
   }

【讨论】:

  • 感谢@Borodin,正如我在上面添加的那样,我有 perl 的基本版本,并且由于 BEGIN 失败而出现错误--编译在 cell_new.pl 第 3 行中止。请你建议我任何解决方案。是的,我只是在学习 perl。
  • @Anthonyj 看起来您可能使用的是相当旧的 Perl 版本,它不包含 autodie 作为核心模块/编译指示。 corelist autodie 显示 perl 5.10.1 是第一个此类版本,您可以检查 perl -v 以查看您的版本是否更早。
猜你喜欢
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2015-01-05
相关资源
最近更新 更多