Perl一次性查找并替换多个(巨大的)字符串

时间:2014-03-06 16:46:37

标签: perl replace bulk

基于映射文件,我需要搜索一个字符串,如果找到,则将替换字符串附加到行尾。 我逐行遍历映射文件并使用下面的perl one-liner,附加字符串。

的问题:

1.Huge find&替换条目:但问题是映射文件有大量条目(~7000个条目)和每个条目的perl单行需要大约1秒,可以归结为~1小时来完成整个替换。 / p>

2.Not Simple Find and Replace:它不是一个简单的Find&更换。它是 - 如果找到字符串,则将替换字符串附加到EOL。 如果没有有效的方法来处理这个问题,我甚至会考虑更换而不是附加。

我在Windows 7 64位环境中使用活动perl。没有* unix支持。

文件样本

Map.csv

findStr1,RplStr1

findStr2,RplStr2

findStr3,RplStr3

.....

findStr7000,RplStr7000

input.csv

col1,col2,col3,findStr1,....col-N

col1,col2,col3,findStr2,....col-N

col1,col2,col3,FIND-STR-NOT-EXIST,....col-N

output.csv (预期输出)

col1,col2,col3,findStr1,....col-N,**RplStr1**

col1,col2,col3,findStr1,....col-N,**RplStr2**

col1,col2,col3,FIND-STR-NOT-EXIST,....col-N

Perl Code Snippet

单行

perl -pe '/findStr/ && s/$/RplStr/' file.csv


open( INFILE, $MarketMapFile ) or die "Error occured: $!";
    my @data = <INFILE>;


    my $cnt=1;  
    foreach $line (@data) {
        eval {          
            # Remove end of line character.
            $line =~ s/\n//g;
            my ( $eNodeBID, $MarketName ) = split( ',', $line );
            my $exeCmd = 'perl -i.bak -p -e "/'.$eNodeBID.'\(M\)/ && s/$/,'.$MarketName.'/;" '.$CSVFile;
            print "\n $cnt Repelacing $eNodeBID with $MarketName and cmd is $exeCmd";
            system($exeCmd);
            $cnt++;
        }
    }       
    close(INFILE);

2 个答案:

答案 0 :(得分:2)

要通过输入CSV一次性完成此操作,最简单的方法是将您的映射存储在哈希中。 7000个条目不是特别大,但是如果你担心将所有这些条目存储在内存中,你可以使用Tie::File::AsHash

#!/usr/bin/perl

use strict;
use warnings;

use Text::CSV;
use Tie::File::AsHash;

tie my %replace, 'Tie::File::AsHash', 'map.csv', split => ',' or die $!;

my $csv = Text::CSV->new({ binary => 1, auto_diag => 1, eol => $/ })
        or die Text::CSV->error_diag;

open my $in_fh, '<', 'input.csv' or die $!;
open my $out_fh, '>', 'output.csv' or die $!;

while (my $row = $csv->getline($in_fh)) {
    push @$row, $replace{$row->[3]};
    $csv->print($out_fh, $row);
}

untie %replace;
close $in_fh;
close $out_fh;

map.csv

foo,bar
apple,orange
pony,unicorn

input.csv

field1,field2,field3,pony,field5,field6
field1,field2,field3,banana,field5,field6
field1,field2,field3,apple,field5,field6

output.csv

field1,field2,field3,pony,field5,field6,unicorn
field1,field2,field3,banana,field5,field6,
field1,field2,field3,apple,field5,field6,orange

我不建议只通过将字段附加到匹配的行来搞砸您的CSV格式,所以如果找不到匹配项,我会添加一个空字段。

要使用常规哈希而不是Tie :: File :: AsHash,只需将tie语句替换为

open my $map_fh, '<', 'map.csv' or die $!;

my %replace = map { chomp; split /,/ } <$map_fh>;

close $map_fh;

答案 1 :(得分:1)

这是未经测试的代码/伪Perl,你需要对其进行修饰(严格,警告等):

 # load the search and replace sreings into memeory
 open($mapfh, "<", mapfile);
 %maplines;
 while ( $mapline = <fh> ) {
   ($findstr, $replstr) = split(/,/, $mapline);
   %maplines{$findstr} = $replstr;
 }
 close $mapfh;

 open($ifh, "<", inputfile);
 while ($inputline = <$ifh>) {                 # read an input line
   @input = split(/,/, $inputline);           # split it into a list

   if (exists $maplines{$input[3]}) {        # does this line match
     chomp $input[-1];                       # remove the new line
     push @input, $maplines{$input[3]};      # add the replace str to the end
     last;                                   # done processing this line
   }
   print join(',', @input);  # or print or an output file 
 }

 close($ihf)