2010-12-02 11 views
7

Encode::decode("utf8", $var)utf8::decode($var)の違いを識別しようとすると、興味深い結果が得られます。私はすでに前者を複数回呼び出すと、最終的には「ワイド文字を含む文字列をデコードできません」というエラーが発生することが判明しました。後者のメソッドは、何度でも何度でも実行できます。Perl:utf8 :: decode vs. Encode :: decode

私が理解していないのは、どのメソッドをデコードするかによって、length関数が異なる結果を返す方法です。この問題は、外部ファイルから「二重にコード化された」utf8テキストを処理しているために発生します。この問題を示すために、私は、U + 00e8、U + 00ab、U + 0086、U + 000aの各行に以下のUnicode文字を含むテキストファイル "test.txt"を作成しました。これらのUnicode文字は、改行文字とともにUnicode文字U + 8acbの二重符号化です。ファイルはUTF8でディスクにエンコードされています。

Length: 7 
utf8 flag: 
Unicode: 
195 168 194 171 194 139 10 
Hex: 
c3a8c2abc28b0a 
============== 
Length: 4 
utf8 flag: 1 
Unicode: 
232 171 139 10 
Hex: 
c3a8c2abc28b0a 
============== 
Length: 2 
utf8 flag: 1 
Unicode: 
35531 10 
Hex: 
e8ab8b0a 

これは私が期待するものです。これは次の出力を与える

#!/usr/bin/perl                                   
use strict; 
use warnings; 
require "Encode.pm"; 
require "utf8.pm"; 

open FILE, "test.txt" or die $!; 
my @lines = <FILE>; 
my $test = $lines[0]; 

print "Length: " . (length $test) . "\n"; 
print "utf8 flag: " . utf8::is_utf8($test) . "\n"; 
my @unicode = (unpack('U*', $test)); 
print "Unicode:\[email protected]\n"; 
my @hex = (unpack('H*', $test)); 
print "Hex:\[email protected]\n"; 

print "==============\n"; 

$test = Encode::decode("utf8", $test); 
print "Length: " . (length $test) . "\n"; 
print "utf8 flag: " . utf8::is_utf8($test) . "\n"; 
@unicode = (unpack('U*', $test)); 
print "Unicode:\[email protected]\n"; 
@hex = (unpack('H*', $test)); 
print "Hex:\[email protected]\n"; 

print "==============\n"; 

$test = Encode::decode("utf8", $test); 
print "Length: " . (length $test) . "\n"; 
print "utf8 flag: " . utf8::is_utf8($test) . "\n"; 
@unicode = (unpack('U*', $test)); 
print "Unicode:\[email protected]\n"; 
@hex = (unpack('H*', $test)); 

print "Hex:\[email protected]\n"; 

:私は、次のperlスクリプトを実行します。 Perlは$ testが単なる一連のバイトであると考えるので、長さはもともと7です。一度デコードした後、perlは$ testがutf8でエンコードされた一連の文字であることを知っています(すなわち、$ testがメモリ内で7バイトであっても、長さが7バイトを返す代わりに、4文字の長さを返します)。 2回目のデコード後、$ testには4バイトが2文字として解釈されます。これはEncode :: decodeが4つのコードポイントをとり、utf8でエンコードされたバイトとして解釈して2文字になるためです。奇妙なことは、代わりにutf8 :: decodeを呼び出すようにコードを修正したときです(utf8 :: decode($ test)ですべての$ test = Encode :: decode( "utf8"、$ test)を置き換えます)

これは

それはperlのように思える
 
Length: 7 
utf8 flag: 
Unicode: 
195 168 194 171 194 139 10 
Hex: 
c3a8c2abc28b0a 
============== 
Length: 4 
utf8 flag: 1 
Unicode: 
232 171 139 10 
Hex: 
c3a8c2abc28b0a 
============== 
Length: 4 
utf8 flag: 1 
Unicode: 
35531 10 
Hex: 
e8ab8b0a 

が最初に、その後、第1のデコード後の文字をカウントし(予想通り)をデコードする前にバイトを数えますが、その後、後に再びバイトをカウント:ほぼ同じ出力を与える、長さの唯一の結果は異なります2番目のデコード(予期しない)。なぜこの切り替えが起こるのでしょうか?これらのデコード機能がどのように機能するかについての私の理解の遅れはありますか?

おかげで、
マット

+1

モジュールを '使用するのではなく'モジュールを '必要とするのはなぜですか? –

+1

私はuse utf8をしていませんでした。なぜなら、あなたのコード自体がutf8でエンコードされていることをperlに伝えているからです(http://perldoc.perl.org/utf8.html)。私はuse dエンコードすることができたと思うが、私はちょうど起こらなかった。 – Matt

答えて

3

あなたがutf8プラグマモジュールから関数を使用することになっていません。 Its documentationと書いてありますので

このプラグマは、スクリプトがUTF-8で書かれていることをPerlに伝える以外には使用しないでください。

Always use the Encode moduleさらに、Checklist for going the Unicode way with Perlの質問を参照してください。 unpackのレベルが低すぎると、エラーチェックも行われません。

あなたはオクテットで E8 AB 86 0AがUTF-8 ダブルエンコーディング文字 newlineの結果であることを前提と間違っています。これは、 のUTF-8エンコードのこれらの文字の表現です。おそらくあなたの側の混乱は、その間違いに由来しているのかもしれません。

lengthが不適切に過負荷になると、長さが文字数またはオクテット単位の長さで特定されることがあります。 Devel::Peekなどの優れたツールを使用してください。

#!/usr/bin/env perl 
use strict; 
use warnings FATAL => 'all'; 
use Devel::Peek qw(Dump); 
use Encode qw(decode); 

my $test = "\x{00e8}\x{00ab}\x{0086}\x{000a}"; 
# or read the octets without implicit decoding from a file, does not matter 

Dump $test; 
# FLAGS = (PADMY,POK,pPOK) 
# PV = 0x8d8520 "\350\253\206\n"\0 

$test = decode('UTF-8', $test, Encode::FB_CROAK); 
Dump $test; 
# FLAGS = (PADMY,POK,pPOK,UTF8) 
# PV = 0xc02850 "\350\253\206\n"\0 [UTF8 "\x{8ac6}\n"] 
+2

応答していただきありがとうございます。 perlのドキュメントでは、utf8モジュールの関数を使うことは大丈夫だと言います。あなたの引用文の後にある文は、 "utf8を使わずに直接使用することができます。"、つまりutf8プラグマを "使用"しないでください(perlキーワードを使用する) )その機能。また、私は "eaab860a"がシングルエンコーディングであることを認識しています。私のファイルには、二重エンコーディングである "c3a8c2abc28b0a"というオクテットが含まれています。私の混乱は、「長さ」機能のバグに由来することが判明しました。 http://www.perlmonks.org/?node_id=874996 – Matt

+8

実際には「あなたのスクリプトがUTF-8で書かれていることをPerlに伝える以外にこのプラグマを使用しないでください。 utf8;を使用してください。これは、「あなたがutf8プラグマモジュールから関数を使用することは想定されていません」という意味ではありません。つまり、プラグマを使用して関数をインポートする必要はありません。 –

関連する問題