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 回目のデコード後に再度バイト数をカウントするようです (予想外)。この切り替えはなぜ起こるのでしょうか?これらのデコード機能がどのように機能するかについて、私の理解に誤りはありますか?
ありがとう、
マット