8

Encode::decode("utf8", $var)との使用の違いを識別しようとして、いくつかの興味深い結果が得られていutf8::decode($var)ます。変数に対して前者を複数回呼び出すと、最終的に「ワイド文字を含む文字列をデコードできません...」というエラーが発生することを既に発見しましたが、後者のメソッドは必要なだけ何度でも実行され、単に false を返します。

私が理解できないのはlength、デコードに使用する方法に応じて関数が異なる結果を返す方法です。外部ファイルからの「二重にエンコードされた」utf8テキストを扱っているため、問題が発生します。この問題を説明するために、次の Unicode 文字を 1 行に含むテキスト ファイル「test.txt」を作成しました: U+00e8、U+00ab、U+0086、U+000a。これらの Unicode 文字は、Unicode 文字 U+8acb と改行文字を二重にエンコードしたものです。ファイルは UTF8 でディスクにエンコードされました。次に、次の perl スクリプトを実行します。

#!/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:\n@unicode\n";
my @hex = (unpack('H*', $test));
print "Hex:\n@hex\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:\n@unicode\n";
@hex = (unpack('H*', $test));
print "Hex:\n@hex\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:\n@unicode\n";
@hex = (unpack('H*', $test));

print "Hex:\n@hex\n";

これにより、次の出力が得られます。

長さ: 7
utf8 フラグ:
ユニコード:
195 168 194 171 194 139 10
16 進数:
c3a8c2abc28b0a
==============
長さ: 4
utf8 フラグ: 1
ユニコード:
232 171 139 10
16 進数:
c3a8c2abc28b0a
==============
長さ: 2
utf8 フラグ: 1
ユニコード:
35531 10
16 進数:
e8ab8b0a

これは私が期待するものです。perl は $test を単なる一連のバイトと見なすため、本来の長さは 7 です。一度デコードした後、perl は $test が utf8 でエンコードされた一連の文字であることを認識します (つまり、7 バイトの長さを返す代わりに、$test がメモリ内に 7 バイトのままであっても、perl は 4 文字の長さを返します)。2 回目のデコードの後、$test には 2 文字として解釈された 4 バイトが含まれます。これは、Encode::decode が 4 つのコード ポイントを取得し、それらを utf8 でエンコードされたバイトとして解釈した結果、2 文字になるためです。奇妙なことは、代わりに utf8::decode を呼び出すようにコードを変更した場合です (すべての $test = Encode::decode("utf8", $test); を utf8::decode($test) に置き換えます)。

これにより、長さの結果のみが異なり、ほぼ同じ出力が得られます。

長さ: 7
utf8 フラグ:
ユニコード:
195 168 194 171 194 139 10
16 進数:
c3a8c2abc28b0a
==============
長さ: 4
utf8 フラグ: 1
ユニコード:
232 171 139 10
16 進数:
c3a8c2abc28b0a
==============
長さ: 4
utf8 フラグ: 1
ユニコード:
35531 10
16 進数:
e8ab8b0a

perl は最初にデコード前にバイト数をカウントし (予想どおり)、最初のデコード後に文字数をカウントしますが、2 回目のデコード後に再度バイト数をカウントするようです (予想外)。この切り替えはなぜ起こるのでしょうか?これらのデコード機能がどのように機能するかについて、私の理解に誤りはありますか?

ありがとう、
マット

4

2 に答える 2

4
于 2010-12-03T14:04:04.570 に答える
2

これはバグであることが判明しました:https ://rt.perl.org/rt3//Public/Bug/Display.html?id=80190 。

于 2011-10-21T18:45:00.860 に答える