基于映射文件,我需要搜索一个字符串,如果找到,则将替换字符串附加到行尾。 我逐行遍历映射文件并使用下面的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);
答案 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)