2

UnicodeとIO::Handleで問題が発生したと思います。私が何か間違ったことをしている可能性が非常に高いです。IO :: Handleから個々のUnicode文字(バイトではなく)を取得および取得解除したい。しかし、私は驚くべきエラーを受け取っています。

#!/usr/local/bin/perl

use 5.016;
use utf8;
use strict;
use warnings;

binmode(STDIN,  ':encoding(utf-8)');
binmode(STDOUT, ':encoding(utf-8)');
binmode(STDERR, ':encoding(utf-8)');

my $string = qq[a Å];
my $fh = IO::File->new();

$fh->open(\$string, '<:encoding(UTF-8)');

say $fh->getc(); # a
say $fh->getc(); # SPACE
say $fh->getc(); # Å LATIN CAPITAL LETTER A WITH RING ABOVE (U+00C5)
$fh->ungetc(ord("Å"));
say $fh->getc(); # should be A RING again.

ungetc()行からのエラーメッセージは、「unicode.plの21行目でUTF-8文字の形式が正しくありません(文字列の予期しない終わり)です。」\x{00c5}「unicode.plの21行目でutf8にマップされません。」しかし、それはキャラクターの正しいヘクスであり、キャラクターにマップする必要があります。

16進エディターを使用して、A-RINGのバイトがUTF-8に対して正しいことを確認しました。

これは、2バイトの文字では問題になるようです。

最後のsayは'\xC5'(文字通り4文字:バックスラッシュ、x、C、5)を出力します。

そして、スカラー変数の代わりにファイルから読み取ることでこれをテストしました。結果は同じです。

これは、darwin-2level用に構築されたperl 5、バージョン16、subversion 2(v5.16.2)です。

そして、スクリプトはUTF-8に保存されます。それが私が最初にチェックしたことでした。

4

2 に答える 2

2

この出力を考えると、これは深刻なUnicode処理のバグが発生していることを証明していると確信しています。

perl5.16.0 ungettest
ungettest 98896 @ Sun Jan  6 16:01:08 2013: sending normal line to kid
ungettest 98896 @ Sun Jan  6 16:01:08 2013: await()ing kid
ungettest 98897 @ Sun Jan  6 16:01:08 2013: ungetting litte z
ungettest 98897 @ Sun Jan  6 16:01:08 2013: ungetting big sigma
ungettest 98897 @ Sun Jan  6 16:01:08 2013: kid looping on parental input
98897: Unexpected fatalized warning: utf8 "\xA3" does not map to Unicode at ungettest line 40, <STDIN> line 1.
 at ungettest line 10, <STDIN> line 1.
    main::__ANON__('utf8 "\xA3" does not map to Unicode at ungettest line 40, <ST...') called at ungettest line 40
98896: parent pclose failed: 65280,  at ungettest line 28.
Exit 255

このプログラムによって生成されます:

#!/usr/bin/env perl

use v5.16;
use strict;
use warnings;
use open qw( :utf8    :std );

use Carp;

$SIG{__WARN__} = sub {  confess "$$: Unexpected fatalized warning: @_" };

sub ungetchar($) {
    my $char = shift();
    confess "$$: expected single character pushback, not <$char>" if length($char) != 1;
    STDIN->ungetc(ord $char);
}

sub debug {
    my $now = localtime(time());
    print STDERR "$0 $$ \@ $now: @_\n";
}

if (open(STDOUT, "|-")                          // confess "$$: cannot fork: $!") {
    $| = 1;
    debug("sending normal line to kid");
    say "From \N{greek:alpha} to \N{greek:omega}.";
    debug("await()ing kid");
    close(STDOUT)                               || confess "$$: parent pclose failed: $?, $!";
    debug("child finished, parent exiting normally");
    exit(0);
}

debug("ungetting litte z");
ungetchar("z")                                  || confess "$$: ASCII ungetchar failed: $!";

debug("ungetting big sigma");
ungetchar("\N{greek:Sigma}")                    || confess "$$: Unicode ungetchar failed: $!";

debug("kid looping on parental input");
while (<STDIN>) {
    chomp;
    debug("kid got $_");
}
close(STDIN)                                    || confess "$$: child pclose failed: $?, $!";
debug("parent closed pipe, child exiting normally");
exit 0;
于 2013-01-06T23:02:34.403 に答える
1

ungetc基になる入力ストリームの前にバイトを追加します。U + 00C5を返すには、ストリームに()ではなく(C3 A5その文字のUTF-8エンコーディング)が含まれている必要があります。代わりにIO::Unreadを使用してください。C5ord("Å")unread

于 2013-01-06T06:17:32.343 に答える