2014-03-06 90 views
0

基於映射文件,我需要搜索字符串,如果找到,則將替換字符串附加到行尾。 我正在逐行遍歷映射文件,並使用下面的perl單行,附加字符串。Perl一次性查找並替換多個(巨大)字符串

問題:

1.Huge找到&替換項:但問題是映射文件條目的數量巨大(〜7000項)和Perl俏皮話需要約1秒,每個條目這歸結爲〜1小時以完成整個更換。

2.不簡單查找和替換:它不是一個簡單的查找&替換。它是 - 如果找到字符串,則將替換字符串附加到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代碼段

一個班輪

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); 
+5

部分爲什麼需要這麼長時間,你分叉爲每一個新的Perl程序循環中的線。你不應該那樣做。 –

+1

您匹配的字符串是否總是位於CSV的第4列? – ThisSuitIsBlackNot

+0

@ThisSuitIsBlackNot Yes.The搜索字符串列的位置始終是固定的 – Siva

回答

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 

輸出。CSV

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

我不建議只追加到匹配的行場搞砸了你的CSV格式,所以我添加一個空場,如果沒有找到匹配。

要使用常規哈希代替領帶::文件:: AsHash,只需更換tie語句

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

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

close $map_fh; 
+0

我需要搜索部分搜索字符串,例如310-120-483338(M)上的483338。我該怎麼辦? – Siva

+0

你的意思是'483338'在映射文件中,'310-120-483338(M)'在輸入文件的第四個字段中? – ThisSuitIsBlackNot

+0

是的...... btw在記憶中的速度比領帶快,並且感謝非匹配行上的空列。我之前沒有想過它! – Siva

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)