2013-06-12 68 views
0

我有一套來自Windows的SHIFT_JIS(日文)編碼csv文件,我嘗試在運行Perl v5.10.1的Linux服務器上使用正則表達式進行字符串替換。在SHIFT_JIS編碼的日文文件上處理Perl文件

這是我的要求: 我希望Perl腳本的正則表達式是人類可讀的(至少對於日本人來說) 也就是說。像這樣: s /北/ 0/g; 而不是它散佈一些十六進制代碼 s/0/g;

現在,我正在Windows上的Notepad ++中編輯Perl腳本,並將需要從csv數據文件搜索到的字符串粘貼到Perl腳本中。

下面我有以下工作的測試腳本:

use strict; 
use warnings; 
use utf8; 

open (IN1, "<:encoding(shift_jis)", "${work_dir}/tmp00.csv") or die "Error: tmp00.csv\n"; 
open (OUT1, "+>:encoding(shift_jis)" , "${work_dir}/tmp01.csv") or die "Error: tmp01.csv\n"; 

while (<IN1>) 
{ 
    print $_ . "\n"; 
    chomp; 
    s/北/0/g; 
    s/10:00/9:00/g;  
    print OUT1 "$_\n"; 
}  

close IN1; 
close OUT1; 

這將成功地與csv文件替換9:00 10:00,但問題是我無法取代北(即。北)與0,除非使用utf8也包含在頂部。

問題:

1)在打開的文檔,http://perldoc.perl.org/functions/open.html,我沒有看到使用UTF8作爲一項要求,除非它是隱含的? a)如果我只使用utf8,則循環中的第一個打印語句會將垃圾字符打印到我的xterm屏幕上。 b)如果我只打開了:encoding(shift_jis),那麼循環中的第一個打印語句將打印日文字符到我的xterm屏幕,但替換不會發生。沒有警告說沒有指定使用utf8。

c)如果我同時使用a)和b),那麼這個例子就有效。

「使用utf8」如何修改在此Perl腳本中使用enoding(shift_jis)調用open的行爲?

2)我也嘗試打開沒有指定任何編碼的文件,Perl不會將文件字符串視爲原始字節,並且如果我在腳本中粘貼的字符串能夠執行正則表達式匹配使用與原始數據文件中的文本相同的編碼?我能夠在這種方式下更早地進行文件名替換,而無需指定任何編碼(請參考我的相關帖子:Perl Japanese to English filename replacement)。

謝謝。

更新1在

測試Perl編寫的簡單定位樣品文件名和文件中的文本替換在日本

在Windows XP中,從.csv數據文件中複製的南字符並複製到剪貼板,然後將其用作文件名(即南.txt)和文件內容(南)。在Notepad ++中,讀取編碼爲UTF-8的文件顯示x93xEC,在SHIFT_JIS下讀取它顯示南。

腳本:

使用下面的Perl腳本south.pl,這將在Linux服務器上用Perl運行5.10

#!/usr/bin/perl 
use feature qw(say); 

use strict; 
use warnings; 
use utf8; 
use Encode qw(decode encode); 

my $user_dir="/usr/frank"; 
my $work_dir = "${user_dir}/test_south"; 

# forward declare the function prototypes 
sub fileProcess; 

opendir(DIR, ${work_dir}) or die "Cannot open directory " . ${work_dir}; 

# readdir OPTION 1 - shift_jis 
#my @files = map { Encode::decode("shift_jis", $_); } readdir DIR; # Note filename could not be decoded as shift_jis 
#binmode(STDOUT,":encoding(shift_jis)");      

# readdir OPTION 2 - utf8 
my @files = map { Encode::decode("utf8", $_); } readdir DIR; # Note filename could be decoded as utf8 
binmode(STDOUT,":encoding(utf8)");       # setting display to output utf8 

say @files;         

# pass an array reference of files that will be modified 
fileNameTranslate(); 
fileProcess(); 

closedir(DIR); 

exit; 

sub fileNameTranslate 
{ 

    foreach (@files) 
    { 
     my $original_file = $_; 
     #print "original_file: " . "$original_file" . "\n";  
     s/南/south/;  

     my $new_file = $_; 
     # print "new_file: " . "$_" . "\n"; 

     if ($new_file ne $original_file) 
     { 
      print "Rename " . $original_file . " to \n\t" . $new_file . "\n"; 
      rename("${work_dir}/${original_file}", "${work_dir}/${new_file}") or print "Warning: rename failed because: $!\n"; 
     } 
    } 
} 

sub fileProcess 
{ 

    # file process OPTION 3, open file as shift_jis, the search and replace would work 
    # open (IN1, "<:encoding(shift_jis)", "${work_dir}/south.txt") or die "Error: south.txt\n"; 
    # open (OUT1, "+>:encoding(shift_jis)" , "${work_dir}/south1.txt") or die "Error: south1.txt\n"; 

    # file process OPTION 4, open file as utf8, the search and replace would not work 
open (IN1, "<:encoding(utf8)", "${work_dir}/south.txt") or die "Error: south.txt\n"; 
    open (OUT1, "+>:encoding(utf8)" , "${work_dir}/south1.txt") or die "Error: south1.txt\n"; 

    while (<IN1>) 
    { 
     print $_ . "\n"; 
     chomp; 

     s/南/south/g; 


     print OUT1 "$_\n"; 
    } 

    close IN1; 
    close OUT1; 
} 

結果:

(BAD)取消註釋選項1和3(註釋選項2和4) 設置:Readdir編碼,SHIFT_JIS;文件打開編碼SHIFT_JIS 結果:文件名替換失敗.. 錯誤:UTF8 「\ X93」 並不在.//south.pl線圖到Unicode 68 \ X93

(BAD)取消註釋選項2和4(註釋選項1和3) 設置:Readdir編碼,utf8;文件打開編碼utf8 結果:文件名替換成功,south.txt生成 但是south1.txt文件內容替換失敗,它的內容爲\ x93()。 錯誤:? 「\ X {FFFD}」 不映射在.//south.pl管線25 到SHIFTJIS ... -AO =(Bx的{} FFFD名爲.txt

(GOOD)取消註釋選項2和3,(註釋選項1和4) 安裝程序:Readdir編碼,utf8;文件打開編碼SHIFT_JIS 結果:文件名替換工作,south.txt生成 South1.txt文件內容替換工作,它有南內容

結論:

我不得不使用不同的編碼方案,此示例才能工作p roperly。 Readdir utf8和文件處理SHIFT_JIS,因爲csv文件的內容是SHIFT_JIS編碼的。

回答

1

一個好的開始就是閱讀the documentation for the utf8 module。它說:

The use utf8 pragma tells the Perl parser to allow UTF-8 in the program text in the current lexical scope (allow UTF-EBCDIC on EBCDIC based platforms). The no utf8 pragma tells Perl to switch back to treating the source text as literal bytes in the current lexical scope.

如果你沒有在你的代碼use utf8這樣做,那麼Perl編譯器假定您的源代碼是在系統的原生單字節編碼。而'北'這個字就沒有意義了。添加雜注告訴Perl,你的代碼包含Unicode字符,並且所有東西都開始工作。

+0

感謝戴夫,你能解釋UTF-8和SHIFT_JIS之間的區別嗎? UTF8是一種編碼方案,所以我的困惑是,如果SHIFT_JIS也是一種(不同的)編碼方案,那麼當我使用utf8編譯指示時,那麼我的源腳本(包含SHIFT_JIS)字符將不再被解釋爲單字節,而是作爲utf8字符。然後我打開:encoding(SHIFT_JIS),文件中的字符將是SHIFT_JIS字符。除非兩種編碼方案相同,否則我不明白這是如何工作的。我無法分辨SHIFT_JIS維基百科頁面是否屬於這種情況。 – frank

+0

我已經更新了一個例子,說明我爲了進行文件名替換和文件內容替換而使用的不同編碼方案。 – frank

+0

文件名的編碼由操作系統決定。你不能改變這一點。文件內容的編碼由寫入文件的人決定。 –