【问题标题】:search and replace some portion of text in a file using perl使用 perl 搜索和替换文件中的某些文本部分
【发布时间】:2021-03-04 13:06:06
【问题描述】:

我编写了一个 perl 脚本,用一些其他文本替换文件中的文本,保持搜索文本的某些部分不变。 但是,我的脚本没有按预期工作,我在 Stackoverflow 中看到了类似的问题并遵循了建议,但脚本仍然没有给出预期的输出。
请参阅我希望在文件中替换的以下文本(突出显示)以及编写的相应脚本

在文件中,我想用“150”替换十进制值。 任何帮助将不胜感激。感谢您的宝贵时间!

#!usr/bin/perl    
  2 
  3 use strict;
  4     use warnings;
  5      
  6     my $filename = 'input_file.txt';
  7      
  8     my $data = read_file($filename);
  9      $data =~ s/(g_clk.*-multiply_by\s\+)\d\+/$1 150/ge;
 10     print "$data\n";
 11     write_file($filename, $data);
 12     exit;
 13      
 14     sub read_file {
 15         my ($filename) = @_;
 16      
 17         open my $in, '<:encoding(UTF-8)', $filename or die "Could not open '$filename' for reading $!";
 18         local $/ = undef;
 19         my $all = <$in>;
 20         close $in;
 21      
 22         return $all;
 23     }
 24      
 25     sub write_file {
 26         my ($filename, $content) = @_;
 27      
 28         open my $out, '>:encoding(UTF-8)', $filename or die "Could not open '$filename' for writing $!";;
 29         print $out $content;
 30         close $out;
 31      
 32         return;
 33     }

【问题讨论】:

  • 提供可复制粘贴的代码和输入/输出文本示例要好得多。作为对试图帮助您的人的一种礼貌,让他们不必输入您想要修复的内容的时间。

标签: file perl replace


【解决方案1】:

以下代码演示了多种方法中的一种

use strict;
use warnings;
use feature 'say';

my $re  = qr/^create_gene_clk .*? g_clk .*? -multiply_by \K\d+/;
my $mul = 150;

while( <DATA> ) {
    chomp;
    s/$re/$mul/;
    say;
}

__DATA__
create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 204 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 324 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 14 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/D)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/E)] -multiply_by 114 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/R)] -multiply_by 001 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/T)] -multiply_by 154 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/Y)] -multiply_by 182 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/U)] -multiply_by 194 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 004 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

create_gene_clk -name bgclk -source [get_pins (5201/U)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name bgclk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name bgclk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

输出

create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 204 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name dft_clk -source [get_pins (5201/C)] -multiply_by 324 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/D)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/E)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/R)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/T)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/Y)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/U)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name g_clk -source [get_pins (5201/C)] -multiply_by 150 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

create_gene_clk -name bgclk -source [get_pins (5201/U)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name bgclk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]
create_gene_clk -name bgclk -source [get_pins (5201/C)] -multiply_by 104 -add -master_clk [get_clk {fin}] [get_p {pll/clk/out}]

【讨论】:

    【解决方案2】:

    据我所知,您的正则表达式中有一个致命错误。

    $data =~ s/(g_clk.*-multiply_by\s\+)\d\+/$1 150/ge;
    #                                ^^   ^^
    

    你已经转义了加号+,这使它失去了它作为量词的特殊含义,现在它只是意味着“匹配一个文字加号”。

    如果您在加号之前删除反斜杠,它应该可以工作。

    然而,这不是你犯的唯一错误。

    • 您使用了/g 全局修饰符,即使您确实不想每行匹配多次。
    • 您使用了/e eval 修饰符,即使您确实不想将替换部分作为 Perl 代码进行评估。

    至于有问题的设计选择:

    • 即使您真的只想每行匹配一次(这可能就是您使用 /g 全局修饰符的原因),但您还是将文件添加到单个变量中,而不是逐行读取。
    • 您在 print "$data\n"; 行中添加了一个额外的换行符。
    • 你用exit结束你的程序,即使程序会在可执行代码结束时自然退出。
    • 如果您仍然想偷懒,最好使用已经发明的模块File::Slurp,而不是重新发明轮子。

    此外,这可以通过“所谓的”单线来解决。这是 Perl 的核心功能,用于就地编辑文件。您可以像这样简单地摆脱困境:

    perl -pe's/g_clk.*-multiply_by \K\d+/150/' input.txt > output.txt
    

    这将写入一个新文件,使用 shell 重定向输出。您还可以使用-i 开关就地编辑文件:

    perl -pi.bak -e's/g_clk.*-multiply_by \K\d+/150/' input.txt
    

    这将保存带有.bak 扩展名的原始文件。不过要小心,因为两次运行该命令仍会覆盖您的原始文件。最好的选择是在尝试就地编辑之前保存永久备份。

    这种风格的程序是这个的短版(不包括就地编辑)

    while (<>) {
        s/g_clk.*-multiply_by \K\d+/150/;
        print;
    }
    

    【讨论】:

    • 感谢 TLP 对我的错误的详细解释。所有 cmets 都非常有帮助..!!
    • @Sonali 你知道你可以对一个答案投赞成票,如果它帮助你解决了你的问题,就将它标记为接受。
    【解决方案3】:

    通过以下方式更改正则表达式:

    $data =~ s/(-multiply_by\s+)\d+/$1 150/g;
    

    它匹配“-multiply_by”和空格 (\s+),后跟 1 个或多个数字 (\d+)。使用括号记住文本($1)。这在第二部分(替换部分)很有用

    UPDATE 1:要替换一个具体的部分(由行号分隔),最好是逐行读取文件,然后使用 $.需要时应用正则表达式的特殊变量。示例:

    open my $in, '<:encoding(UTF-8)', $filename_in or die $!;
    open my $out, '<:encoding(UTF-8)', $filename_out or die $!;
    
    while( my $data = <$in> ) {
        if( $. >= 4 && $. <= 12) {
            # Replace only if line number ($.) is between 4 and 12
            $data =~ s/(-multiply_by\s+)\d+/$1 150/g;
        }
        # Print at output the handled line
        print $out $data;
    }
    
    close $in;
    close $out;
    

    更新 2:要替换具体部分(由同一行的其他值分隔),请像这样搜索您的条件:

    open my $in, '<:encoding(UTF-8)', $filename_in or die $!;
    open my $out, '<:encoding(UTF-8)', $filename_out or die $!;
    
    while( my $data = <$in> ) {
        if( $data =~ /-name glck / ) {
            # Replace only if line has "-name glck" text
            $data =~ s/(-multiply_by\s+)\d+/$1 150/g;
        }
        # Print at output the handled line
        print $out $data;
    }
    
    close $in;
    close $out;
    

    【讨论】:

    • 非常感谢 Miguel 的宝贵时间..!!!,但是,我只想替换具有“glck”的行(文件 4 到 12 中的行号),您共享的脚本将用 150 替换所有行。我想知道,如果我在替换命令中包含“gclk.*”,为什么脚本不起作用。
    • 感谢 Miguel 提供不同观点的解决方案..!!!
    猜你喜欢
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多