2012-07-13 178 views
0

早些時候我在循環內工作,如果匹配成功,它會從第二個循環文件​​中替換整個字符串。現在我有一個稍微不同的情況。我試圖用第二個循環的字符串替換第一個循環的子字符串。它們都是csv文件並以分號分隔。我想要替換的特殊字符:從數碼到人物本身的第一個文件是這樣的:用第二個csv文件中的字符串替換子字符串

1;2;bla&#322blabla &#261bla;7;8 
3;4;bl&#261blabla;9;10 
2;3;blablabla&#261ał8;9 

和第二個文件的數字代碼和相應的字符:

Ą;Ą 
ą;ą 
Ǟ;Ǟ 
Á;Á 
á;á 
Â;Â 
ł;ł 

第二個文件中的第一個分號屬於相應字符的數字代碼,不應該用於分割文件。結果應該是:

1;2;blałblabla ąbla;7;8 
3;4;bląblabla;9;10 
2;3;blablablaąał;8;9 

這是我的代碼。我怎樣才能解決這個問題?

use strict; 
use warnings; 

my $inputfile1 = shift || die "input/output!\n"; 
my $inputfile2 = shift || die "input/output!\n"; 
my $outputfile = shift || die "output!\n"; 

open my $INFILE1, '<', $inputfile1 or die "Used/Not found :$!\n"; 
open my $INFILE2, '<', $inputfile2 or die "Used/Not found :$!\n"; 
open my $OUTFILE, '>', $outputfile or die "Used/Not found :$!\n"; 

my $infile2_pos = tell $INFILE2; 

while (<$INFILE1>) { 
s/"//g; 
my @elements = split /;/, $_; 
seek $INFILE2, $infile2_pos, 0; 

    while (<$INFILE2>) { 
    s/"//g; 
    my @loopelements = split /;/, $_; 

    #### The problem part #### 
    if (($elements[2] =~ /\&\#\d{3}\;/g) and (($elements[2]) eq ($loopelements[0]))){ 
     $elements[2] =~ s/(\&\#\d{3}\;)/$loopelements[1]/g; 
     print "$2. elements[2]\n"; 
       } 
    #### End problem part ##### 
    } 

my $output_line = join(";", @elements); 
print $OUTFILE $output_line; 
#print "\n" 
} 

close $INFILE1; 
close $INFILE2; 
close $OUTFILE; 

exit 0; 

回答

2

假設你的字符代碼是標準的Unicode實體,你最好用HTML::Entities來解碼它們。

該程序處理您在第一個文件中顯示的數據,並完全忽略第二個文件。輸出似乎是你想要的。

use strict; 
use warnings; 

use HTML::Entities 'decode_entities'; 

binmode STDOUT, ":utf8"; 

while (<DATA>) { 
    print decode_entities($_); 
} 

__DATA__ 
1;2;bla&#322blabla &#261bla;7;8 
3;4;bl&#261blabla;9;10 
2;3;blablabla&#261a&#322;8;9 

輸出

1;2;blałblabla ąbla;7;8 
3;4;bląblabla;9;10 
2;3;blablablaąał8;9 
+0

謝謝!這很容易:) – Jan 2012-07-16 09:07:16

+0

@Borodin所以在設置binmode到utf8之後,這是否只適用於打印?如果我將decode_entities的返回值存儲到var,它會起作用嗎? – Rooster 2014-02-13 00:15:44

0

您在;每次出現,然後將其刪除分裂您@elements。你不會在你的數據中找到它,你的正則表達式中的分號永遠不能匹配,所以不會進行替換。

無論如何,使用seek有點令我感到困擾。當你擁有的替換代碼(< 5000)合理數量的,你可以考慮將它們放入一個哈希:

my %subst; 
while(<$INFILE2>){ 
    /^&#(\d{3});;(.*)\n/; 
    $subst{$1} = $2; 
} 

那麼我們可以這樣做:

while(<$INFILE1>){ 
    s| &# (\d{3}) | $subst{$1} // "&#$1" |egx; 
     # (don't try to concat undef 
     # when no substitution for our code is defined) 
    print $OUTFILE $_; 
} 

我們不必分割的文件或者如果替換應該在INFILE1中的任何地方發生,則將它們視爲CSV數據。我的解決方案應該加快一點(僅解析INFILE2一次)。在這裏,我假定你的輸入數據是正確的,數字代碼不是以分號結尾,而是以長度結尾。 (即m/&#\d{3}/

如果您在字符編碼方面有問題,您可能需要使用:uft8和/或use Encode或類似文件打開文件。

+0

哈哈這麼愚蠢的我!我想這是星期五:P會從來沒有想過這種方法!現在就試試吧:)所以只是爲了確保:將整個seek/tell部分放在代碼之外? – Jan 2012-07-13 14:37:05

相關問題