2013-10-28 68 views
2

我正在修改一個Perl腳本,它以製表符分隔的格式讀取一系列UCS-2LE編碼文件,但是當字符串包含擴展拉丁字符集之外的字符時,我無法分離製表符上的字符串。當字符串包含非拉丁字符時,在Perl中使用split()函數的問題Perl中的問題

下面是我從這些文件中讀取(製表符分隔)的樣本行:

adını transcript asr turkish 

當我有我的劇本寫這幾行輸出文件,試圖調試這個問題,這是它正在寫的:

ad1Ů1ĉtranscript asr turkish 

它似乎不識別土耳其字符後面的製表符。只有當單詞以非拉丁字符結尾時(以及與標籤相鄰),纔會發生這種情況。

下面是代碼塊的一部分,其中寫入到輸出文件中發生和串分解發生的情況:

for my $infile (@ARGV){ 
    if (!open (INFILE, "<$infile")){ 
     die "Couldn't open $infile.\n"; 
    }  

binmode (OUTFILE, ":utf8"); 

while (<INFILE>) { 
    chomp; 
    $tTot++; 

    if ($lineNo == 1) {     
     $_ = decode('UCS-2LE', $_);  
    } 
    else { 
     $_ = decode('UCS-2', $_); 
    }  

    $_ =~ s/[\r\n]+//g;  
    my @foo = split('\t'); 

    my $orth = $foo[0]; 
    my $tscrpt = $foo[1]; 
    my $langCode = $foo[3]; 

    if (exists $codeHash{$langCode}) { 
     unless ($tscrpt eq '') { 
     check($orth, $tscrpt, $langCode); 
     } 
    } 
    else { 
     print OUTFILE "Unknown language code $langCode at line $lineNo.\n"; 
     print OUTFILE $_; # printing the string that's not being split correctly 
     print OUTFILE "\n"; 
     $tBad++; 
    } 
    } 

該腳本的目的是檢查的是,對於在輸入文件中的每一行,語言代碼是有效的,並根據該代碼根據我們的轉錄系統檢查每個單詞的轉錄是否爲「合法」。

這裏是我試過到目前爲止:

  1. 改變輸入字符串的編碼,因爲它們可以讀取到 UTF-8,UTF-16或UTF-16LE
  2. 更改分割()字符爲'\ w', /[[:blank:]] /,\ p {Blank},\ x {09}和\ N {U + 0009}。
  3. 閱讀的Perl 統一& perlrebackslash文檔和其他遠程 相關的帖子我已經能夠找到各種網站上

有沒有人有任何建議,其他的東西我可能會嘗試一下呢?提前致謝!

我還應該提到,我無法控制輸入文件編碼和輸出文件編碼;我必須讀取UCS-2LE並輸出UTF-8。

+1

您應該能夠在5行以下的'split'中演示問題。並且不要忽略在更新中處理輸出編碼的行。另外,請提供即將到來的演示失敗的輸入。 'od -t x1 file'將以不會損壞的格式提供。 – ikegami

+0

btw,'$ _ = decode('UCS-2LE',$ _); s/^ \ x {FEFF} //;'是解碼文件的一種更簡單的方法。更好的辦法是在'open'中使用'<:raw:encoding(UCS-2le):crlf''而不是''<'''。 – ikegami

+0

您的'split'到'@ foo'似乎與您的輸出大部分無關,只是觸發了幾條錯誤消息。在's'聲明之下沒有任何東西似乎對您的(未編碼)'$ _'打印有任何影響。 – tjd

回答

0

感謝大家的意見和一些進一步的研究,我想通了,如何解決這個問題,它比我想象的略有不同;它變成了split()問題和編碼問題的組合。我不得不在for循環中使用隱式open來添加編碼,而是跳過文件開頭的前兩個字節。

這裏的修正,工作代碼看起來像什麼,因爲我張貼在我的問題的部分:

for my $infile (@ARGV){ 
    my $outfile = $infile . '.out'; 

    # SOLUTION part 1: added explicit open statement 
    open (INFILE, "<:raw:encoding(UCS-2le):crlf", $infile) or die "Error opening $infile: $!"; 

    # SOLUTION part 2: had to skip the first two bytes of the file 
    seek INFILE, 2, 0; 

    if (!open (OUTFILE, ">$outfile")) { 
     die "Couldn't write to $outfile.\n"; 
    } 

    binmode (OUTFILE, ":utf8"); 
    print OUTFILE "Line#\tOriginal_Entry\tLangCode\tOffending_Char(s)\n"; 

    $tBad = 0; 
    $tTot = 0; 
    $lineNo = 1; 

while (<INFILE>) { 
    chomp; 
    $tTot++; 

    # SOLUTION part 3: deleted the "if" block I had here before that was handling encoding 

    # Rest of code in the original block is the same  
} 

我的代碼現在可以正確識別鄰近字符無法擴展拉丁集的一部分製表符,並分割上標籤,因爲它應該。

注意:另一種解決方案是將外來詞用雙引號括起來,但在我們的例子中,我們不能保證我們的輸入文件將被格式化。

感謝所有評論和幫助我的人!

1

你應該首先打開正確的編碼文件(不是我知道這是否是正確的編碼,但我相信你的話)。那麼你就需要調用解碼():

open(my $fh, "<:encoding(UCS-2LE)", $file) or die "Error opening $file: $!"; 
while (<$fh>) { 
    ... 
} 
相關問題