ここ数時間、Perl プログラムのバグと戦っています。私が何か間違っているのか、インタープリターが間違っているのかはわかりませんが、コードは決定論的である必要がありますが、IMO は非決定論的です。また、古い Debian Lenny (Perl 5.10.0) と Debian Wheezy (Perl 5.14.2) にアップグレードしたばかりのサーバーでも同じ動作を示します。それは、次の Perl コードに要約されます。
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
my $c = "";
open C, ">:utf8", \$c;
print C "š";
close C;
die "Does not happen\n" if utf8::is_utf8($c);
print utf8::decode($c) ? "Decoded\n" : "Undecoded\n";
Perl 5 インタープリターを厳密モードで初期化し、警告を有効にして、文字列 (バイト文字列ではなく) と名前付きの標準ストリームを UTF8 でエンコードします (UTF-8 の内部概念ですが、完全な UTF-8 に変更しても違いはありません)。 )。次に、「メモリ内ファイル」(スカラー変数) へのファイル ハンドルを開き、2 バイトの UTF-8 文字を 1 つ出力し、閉じたときに変数を調べます。
スカラー変数の UTF8 ビットが常にオフになります。ただし、バイト文字列 ( を介して文字列に変換されるutf8::decode()
) が含まれることもあれば、UTF8 ビットをオンにする必要がある文字列 ( ) が含まれることもありますEncode::_utf8_on()
。
コードを繰り返し (Bash 経由で 1000 回) 実行するUndecoded
とDecoded
、ほぼ同じ頻度で出力されます。「ファイル」に書き込む文字列を変更すると、たとえば最後に改行を追加すると、Undecoded
消えます。成功し、ループ内の同じ元の文字列に対して試行するutf8::decode
と、インタープリターの同じインスタンスで成功し続けます。ただし、失敗すると、失敗し続けます。
観察された行動の説明は何ですか? 文字列と一緒にスカラー変数へのファイル ハンドルを使用するにはどうすればよいですか?
バッシュ遊び場:
for i in {1..1000}; do perl -we 'use strict; use utf8; binmode STDOUT, ":utf8"; binmode STDERR, ":utf8"; my $c = ""; open C, ">:utf8", \$c; print C "š"; close C; die "Does not happen\n" if utf8::is_utf8($c); print utf8::decode($c) ? "Decoded\n" : "Undecoded\n";'; done | grep Undecoded | wc -l
参考までに、確実に確認するために、ペダンティックなエラー処理を備えたバージョンも作成しましたが、結果は同じでした。
#!/usr/bin/perl
use warnings;
use strict;
use utf8;
binmode STDOUT, ":utf8" or die "Cannot binmode STDOUT\n";
binmode STDERR, ":utf8" or die "Cannot binmode STDERR\n";
my $c = "";
open C, ">:utf8", \$c or die "Cannot open: $!\n";
print C "š" or die "Cannot print: $!\n";
close C or die "Cannot close: $!\n";
die "Does not happen\n" if utf8::is_utf8($c);
print utf8::decode($c) ? "Decoded\n" : "Undecoded\n";