【问题标题】:Perl: Replace strings in multiple files with array entryPerl:用数组条目替换多个文件中的字符串
【发布时间】:2015-07-01 21:30:18
【问题描述】:

我正在寻找一种简单的方法来替换多个文本文件中的字符串。在第一个文件中,字符串应替换为数组@arrayF 的第一个元素;在第二个文件中,字符串必须替换为第二个条目等。

我想替换;size=\d+,其中\d+ 是任意数字的通配符。

这是我目前所拥有的:

#!/usr/bin/perl -w

use strict;
use warnings;

my $counter = 0;
my @arrayF  = '/Users/majuss/Desktop/filelist.txt>';  # Reads all lines into array
my @files   = '/Users/majuss/Desktop/New_Folder/*'; #get Files into an array

foreach my $file ( @files ) {
  $file =~ s/;size=\d+/$arrayF[$counter]/g; #subst. 
  print
  $counter++; #increment array index
}

它返回一个零并且什么都没有发生。

我知道如何在单行中做到这一点,但我不知道如何在那里实现数组。

【问题讨论】:

  • 您可能希望在末尾使用选项 /ge 而不仅仅是 /g。见 perldoc perlre
  • 您的“@files”没有扩展模式。你需要my @files = glob ( '/Users/majuss/Desktop/New_Folder/*' ); 你也没有打开或阅读'filelist.txt' - 你需要使用open
  • 注释Reads all lines into arrayget Files into an array 的行没有这样做。您需要在第一种情况下打开文件并读取它,在第二种情况下使用glob。另外,请不要在本地标识符中使用大写字母,并且不要在 shebang 行中使用-w 以及use warnings;只是后者是正确的
  • 如果您有-w 开关,则不需要use warnings(反之亦然);他们做同样的事情。如果每行只有一个 ;size= 字符串,则您的正则表达式中不需要 /g 。否则,正如其他人所指出的那样,您不是在阅读文件列表或阅读每个文件,也不是真正做您打算做的任何事情。 :-)
  • @mwp:鉴于 OP 的代码根本不做任何文件 IO,我认为你的 cmets 是多余的

标签: arrays regex perl


【解决方案1】:

请注意我在您的问题下方评论的这些要点

  • 注释Reads all lines into array 的行没有这样做。它只是将@arrayF 设置为一个包含字符串/Users/majuss/Desktop/filelist.txt> 的单元素列表。您可能需要打开文件并将其内容读入数组

  • 注释get Files into an array 的行没有这样做。它只是将@files 设置为一个包含字符串/Users/majuss/Desktop/New_Folder/* 的单元素列表。您可能需要使用glob 将通配符扩展为文件列表

  • 声明

    $file =~ s/;size=\d+/$arrayF[$counter]/g
    

    正在尝试修改包含文件名称的变量$file。大概您打算编辑该文件的内容,因此您必须先打开并阅读它

  • 请不要在本地标识符中使用大写字母

  • 不要在shebang线上使用-w以及use warnings;只是后者是正确的

这似乎符合您的要求,但请注意它是未经测试的,除非我已经检查过它是否可以编译。请注意您有原始文件的备份,因为此代码会用修改后的数据覆盖原始文件

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use autodie;

my $replacement_text = '/Users/majuss/Desktop/filelist.txt';
my $file_glob        = '/Users/majuss/Desktop/New_Folder/*';

my @replacement_text = do {
  open my $fh, '<', $replacement_text;
  <$fh>;
};
chomp @replacement_text;

my $i = 0;

for my $file ( glob $file_glob ) {

  my $contents = do {
    open my $in_fh, '<', $file;
    local $/;
    <$in_fh>;
  };

  $contents =~ s/;size=\d+/$replacement_text[$i]/g;

  open my $out_fh, '>', $file;
  print $out_fh $contents;

  ++$i;
}

【讨论】:

  • 我认为您在do 中缺少&lt;$fh&gt; 来设置@file_list。我想你想要print {$out_fh} $contents$out_fh-&gt;print($contents) 在最后。正如我在其他地方指出的那样,/g 是多余的。
  • @mwp:谢谢。我同意读取的丢失文件,但我的print $out_fh $contents 很好,如果文件中多次出现该模式,则需要/g 修饰符
  • 当然。如果不期望多次出现,这在计算上是浪费的,但这可能是目前 OP 的问题中最少的一个。
【解决方案2】:
  • 您没有打开 filelist.txt 并阅读它。

这样做你需要:

open ( my $input, "<", '/Users/majuss/Desktop/filelist.txt' ) or die $!;
my @arrayF = <$input>;
close ( $input );
  • 您需要使用glob 来搜索这样的目录模式。

像这样:

foreach my $file ( glob ( '/Users/majuss/Desktop/New_Folder/*' ) {
      # stuff
}
  • 要在文件中进行搜索和替换,实际上与单行有点不同。您可以在perlrun 中查看“就地编辑”——但这是 perl 试图伪装成sed 的地方。我想你可以试试看——perlvar 中有一个选项:

$^我 就地编辑扩展的当前值。使用 undef 禁用就地编辑。 助记符:-i 开关的值。

这个答案可能会提供一些见解: In-place editing of multiple files in a directory using Perl's diamond and in-place edit operator

相反,您可以:

foreach my $file ( glob  ( '/Users/majuss/Desktop/New_Folder/*' ) {
     open ( my $input_fh, "<", $file ) or die $!;
     open ( my $output_fh, ">", "$file.NEW" ) or die $!;
     my $replace = shift ( @arrayF );
     while ( my $line = <$input_fh> ) {
        $line =~ s/;size=\d+/$replace/g; 
        print {$output_fh} $line;
     }
     close ( $input_fh );
     close ( $output_fh );
      #rename 'output'. 
}

【讨论】:

  • 关闭。你的括号在第一行是错误的,我认为你需要设置 $replace before 内部while循环(每个文件一个值)。正则表达式上的 /g 是多余的。
猜你喜欢
  • 2022-01-08
  • 1970-01-01
  • 2016-08-02
  • 1970-01-01
  • 2020-07-23
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
  • 2013-05-25
相关资源
最近更新 更多