2013-01-09 23 views
3

我有這樣的字符串:轉換字符串中的字符

Why RUNAS Windows \xee\x80\x80\x45xplorer\xee\x80\x81 Doesn\xe2\x80\x99t 
Work After Installing IE7 St\xc3\xa5le 

我得到通過讀取XML文件。這是一個UTF-8字符串。現在我想,這樣我可以打印它的等效Unicode字符:

Why RUNAS Windows Explorer Doesn’t Work After Installing IE7 Ståle 

我嘗試了一個小程序:

use strict; 
use utf8; 
use Encode; 

my $str = "Why RUNAS Windows \xee\x80\x80\x45xplorer\xee\x80\x81 Doesn\xe2\x80\x99t Work After Installing IE7 St\xc3\xa5le"; 
print $str; 

和它的工作!

問題是,當我試圖從文件中讀取字符串,它不是轉換。所以下面不會產生unicode輸出:

use strict; 
use utf8; 
use Encode; 
my $str = <DATA>; 
$str = decode("utf8", $str); 
open OUT, ">", "o.txt" or die; 
binmode(OUT,":utf8"); 
print OUT $str; 
__DATA__ 
Why RUNAS Windows \xee\x80\x80\x45xplorer\xee\x80\x81 Doesn\xe2\x80\x99t Work After Installing IE7 St\xc3\xa5le 
+4

你倒入靈魂你。無論誰決定你的XML格式需要將UTF字符編碼爲僞轉義的ASCII碼需要悔改。 –

+0

HI @RobertP:任何想法如何得到這個工作? – gameover

+0

請注意您收到的「寬字符」警告(如果您使用'使用警告;'如您所願)。你忘了編碼你的輸出。爲了修復這個bug,添加'use open':std',':encoding(UTF-8)';'(或者終端所期望的任何編碼)。 – ikegami

回答

1

使用替換與評估將每個代碼更改爲相應的字節。沒有use utf8也不use Encode需要:

#!/usr/bin/perl 
use warnings; 
use strict; 

my $str = <DATA>; 
$str =~ s/\\x(..)/chr hex $1/eg; 
open my $OUT, '>', 'o.txt' or die $!; # No binmode utf8 - byte semantics needed! 
print $OUT $str; 

__DATA__ 
Why RUNAS Windows \xee\x80\x80\x45xplorer\xee\x80\x81 Doesn\xe2\x80\x99t Work After Installing IE7 St\xc3\xa5le 
+0

這不會很正常。他顯示的逃逸是多字節的unicode字符,因此將它們轉換爲單字節字符會導致錯誤的字符。 –

+0

@RobertP:哦,謝謝。固定。 – choroba

5

的區別你的兩個例子之間的是,在第一個例子中的反斜槓進行插補以字節爲單位,因爲它的編譯,而在第二個例子中,他們是文字文本。在第二個示例中,您正在讀取一系列字符「\」,「x」,「e」,「e」,但第一個字符將其轉換爲內存中的一個unicode字符。

如果XML文件包含unicode字符,Perl可以很好地讀取它們;他們不需要像圖中那樣逃脫。

如果您必須將這些unicode字符保留爲字符序列,請考慮使用CPAN庫對它們進行解碼。一目瞭然,它看起來像Encode::Escape會滿足您的需求:

#!/usr/bin/perl 
use strict; 
use warnings; 
use Encode::Escape; 

while (<DATA>) { 
    chomp; 
    print decode 'unicode-escape', $_; # convert byte references to (utf-8) bytes 
} 

__DATA__ 
Why RUNAS Windows \xee\x80\x80\x45xplorer\xee\x80\x81 Doesn\xe2\x80\x99t 
Work After Installing IE7 St\xc3\xa5le 

有可能是別人。

+0

我已經添加了代碼示例。 – jfs

4

這是很明顯的:

print "abc\n"; # Prints <abc> 

<DATA>;   # Doesn't print <abc> 
__DATA__ 
print "abc\n"; 

所以這應該是毫不奇怪:

"\x61";   # Evaluates to string <a> 

<DATA>;   # Doesn't evaluate to string <a> 
__DATA__ 
"\x61" 

你混淆字符串(一個Perl運營商)和字符串(字符序列)。 readline不會將您的數據文件作爲Perl代碼執行。 (即使是這樣,你也錯過了引號。)如果你想轉換你讀的字符串,你將不得不告訴Perl來轉換它們。

s/ \\x(..) | \\([^a-zA-Z]) | \\(.)/
    defined($1) ? chr(hex($1)) : 
    defined($2) ? $2 : 
    do { warn "Unknown escape \\$3\n"; "\\$3" } 
/sexg;