3

Unicode の問題で困惑したときに、クエリ文字列の解析をテストする例を書き上げようとしています。つまり、文字「オメガ」(Ω) は正しくデコードされていないようです。

  • ユニコード: U+2126
  • 3 バイト シーケンス: \xe2\x84\xa6
  • エンコードされた URI: %E2%84%A6

そこで、URI::Encode を使用して Unicode クエリ文字列を「デコード」できることを確認するこのテスト プログラムを作成しました。

use strict;                                                                                                                                                                    
use warnings;
use utf8::all;    # use before Test::Builder clones STDOUT, etc.
use URI::Encode 'uri_decode';
use Test::More;

sub parse_query_string {
    my $query_string = shift;
    my @pairs = split /[&;]/ => $query_string;

    my %values_for;
    foreach my $pair (@pairs) {
        my ( $key, $value ) = split( /=/, $pair );
        $_ = uri_decode($_) for $key, $value;
        $values_for{$key} ||= [];
        push @{ $values_for{$key} } => $value;
    }
    return \%values_for;
}

my $omega = "\N{U+2126}";
my $query = parse_query_string('alpha=%E2%84%A6');
is_deeply $query, { alpha => [$omega] }, 'Unicode should decode correctly';

diag $omega;
diag $query->{alpha}[0];

done_testing;

そして、テストの出力:

query.t .. 
not ok 1 - Unicode should decode correctly
#   Failed test 'Unicode should decode correctly'
#   at query.t line 23.
#     Structures begin differing at:
#          $got->{alpha}[0] = 'â¦'
#     $expected->{alpha}[0] = 'Ω'
# Ω
# â¦
1..1
# Looks like you failed 1 test of 1.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/1 subtests 

Test Summary Report
-------------------
query.t (Wstat: 256 Tests: 1 Failed: 1)
  Failed test:  1
  Non-zero exit status: 1
Files=1, Tests=1,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.05 cusr  0.00 csys =  0.09 CPU)
Result: FAIL

ここで URI::Encode が壊れているように見えますが、URI::Escape に切り替えて uri_unescape 関数を使用すると、同じエラーが報告されます。私は何が欠けていますか?

4

4 に答える 4

7

URIエンコードされた文字は単にutf-8シーケンスを表し、URI::EncodeとURI::Escapeは単にそれらをutf-8バイト文字列にデコードし、どちらもバイト文字列をUTF-8としてデコードしません(これは正しい動作です。汎用URIデコードライブラリ)。

言い換えれば、あなたのコードは基本的にそうします: is "\N{U+2126}", "\xe2\x84\xa6"そしてそれは失敗します、なぜなら比較すると、perlは後者を3文字の長さのlatin-1文字列としてアップグレードするからです。

入力値をEncode::decode_utf8afterで手動でデコードするuri_decodeか、代わりにエンコードされたutf8バイトシーケンスを比較する必要があります。

于 2012-04-10T10:06:12.563 に答える
5

URIエスケープはオクテットを表し、文字エンコードについては何も知らないため、UTF-8オクテットから文字に自分でデコードする必要があります。例:

$_ = decode_utf8(uri_decode($_)) for $key, $value;
于 2012-04-10T10:06:52.177 に答える
4

この問題は、問題に関する独自の説明の中で誤った詳細に見られる場合があります。あなたが扱っているのは、実際には次のとおりです。

  • Unicode コードポイント: U+2126
  • コードポイントの UTF-8 エンコード: \xe2\x84\xa6
  • コードポイントの UTF-8 エンコードの URI エンコード: %E2%84%A6

問題は、エンコーディングの 1 つだけを元に戻したということです。

解決策はすでに提示されています。別の説明を提示したかっただけです。

于 2012-04-10T16:05:16.140 に答える
0

Why does modern Perl avoid UTF-8 by default? をご覧になることをお勧めします。このトピックに関する徹底的な議論のために。

私はそこでの議論に追加します:

  • ページ上に奇妙なグリフがたくさんあることに気付くでしょう。これは作者側の意図的なものでした。
  • スレッドで推奨されている Symbola フォントを試してみましたが、Win 7.YMMV ではひどく見えました。
  • なぜ最新の Perl はデフォルトで UTF-8 を回避するのですか? 頻繁に行うと、うつ病になり、人生の選択について長引く疑いが生じる可能性があります。
于 2012-04-10T13:20:24.477 に答える