7

chr恐ろしいことに、ユニコードでは機能しないことがわかりましたが、何かは機能します。マニュアルページはほとんど明確です

文字セット内のその NUMBER で表される文字を返します。たとえば、chr(65)" は ASCII または Unicode の「A」であり、chr(0x263a) は Unicode スマイリー フェイスです。

実際、私はスマイリーを使用して印刷できます

perl -e 'print chr(0x263a)'

しかし、chr(0x00C0)うまくいきません。私の perl v5.10.1 は少し古いようですが、ソース コードにさまざまな奇妙な文字を貼り付けると、すべて問題ありません。

use utf8とのような面白いことを試しましたが、私のバージョンでは機能しないなどの面白いことは試していません。use encoding 'utf8'デコードするバイト配列がないため、デコードする必要がないことを確認するために で遊んでいました。以前よりもはるかに多くのドキュメントを読み、かなりの数の興味深いものを見つけましたが、役に立ちませんでした。一種のUnicode バグのように見えますが、使用可能な解決策はありません。さらに、文字列のセマンティクス全体は気にしません。必要なのは単純な関数だけです。use v5.12use feature 'unicode_strings'Encode::decode

では、たとえばreal_chr(0xC0) eq 'À'保持されるように、数値をそれに対応する単一の文字からなる文字列に変換するにはどうすればよいでしょうか?


私が得た最初の答えは、IOに関するすべてを説明していますが、その理由はまだわかりません

#!/usr/bin/perl -w
use strict;
use utf8;
use encoding 'utf8';

print chr(0x00C0) eq 'À' ? 'eq1' : 'ne1', " - ", chr(0x263a) eq '☺' ? 'eq1' : 'ne1', "\n";

print 'À' =~ /\w/ ? "match1" : "no_match1", " - ", chr(0x00C0) =~ /\w/ ? "match2" : "no_match2", "\n";

版画

ne1 - eq1
match1 - no_match2

これは、手動で入力された'À'が と異なることを意味しchr(0x00C0)ます。さらに、前者は単語の構成文字であり (正しい!)、後者はそうではありません (ただし、そうあるべきです!)。

4

1 に答える 1

11

初め、

perl -le'print chr(0x263A);'

バギーです。Perl は、次のようなことも教えてくれます。

Wide character in print at -e line 1.

それは「働いている」とは言えません。したがって、それらはあなたが望むものを提供できないという点で異なりますが、次のどちらもあなたが望むものを提供しません:

perl -le'print chr(0x263A);'

perl -le'print chr(0x00C0);'

これらの Unicode コード ポイントの UTF-8 エンコードを適切に出力するには、Unicode ポイントを UTF-8 でエンコードするように Perl に指示する必要があります。

$ perl -le'use open ":std", ":encoding(UTF-8)"; print chr(0x263A);'
☺

$ perl -le'use open ":std", ":encoding(UTF-8)"; print chr(0x00C0);'
À

では、「理由」について。

ファイル ハンドルはバイトしか送信できないため、特に指定しない限り、Perl ファイル ハンドルはバイトを想定します。つまり、指定した文字列にはprintバイト以外を含めることはできません。つまり、255 を超える文字を含めることはできません。出力は、指定したものとまったく同じです。

$ perl -e'print map chr, 0x00, 0x65, 0xC0, 0xF0' | od -t x1
0000000 00 65 c0 f0
0000004

これは便利です。これはあなたが望むものとは異なりますが、それは間違いではありません。何か違うものが必要な場合は、必要なものを Perl に伝えるだけです。

レイヤーを追加すること:encodingで、ハンドルは Unicode 文字の文字列、または私が「テキスト」と呼んでいる文字列を期待するようになりました。レイヤーは、テキストをバイトに変換する方法を Perl に指示します。

$ perl -e'
   use open ":std", ":encoding(UTF-8)";
   print map chr, 0x00, 0x65, 0xC0, 0xF0, 0x263a;
' | od -t x1
0000000 00 65 c3 80 c3 b0 e2 98 ba
0000011

chrUnicode を知らない、または気にしないあなたの権利。lengthsubstrordおよび と同様に、Unicode 関数ではなく、基本的な文字列関数を実装しますreversechrこれは、テキスト文字列の操作に使用できないという意味ではありません。これまで見てきたように、問題は文字列にあるのではなくchr、文字列を作成した後に行ったことにありました。

文字は文字列の要素であり、文字は数字です。つまり、文字列は単なる一連の数字です。これらの数値を Unicode コード ポイント (テキスト) として扱うか、パックされた IP アドレスとして扱うか、温度測定値として扱うかは、完全にユーザーと、文字列を渡す関数に依存します。

オペランドとして受け取った文字列に意味を割り当てる演算子の例を次に示します。

  • m//Unicode コード ポイントの文字列が必要です。
  • connectsockaddr_in構造を表す一連のバイトが必要です。
  • print:encodingバイトのシーケンスを期待せずにハンドルを使用します。
  • print:encodingUnicode コード ポイントのシーケンスを期待するハンドルを使用します。

では、たとえば real_chr(0xC0) eq 'À' が成り立つように、数値をそれに対応する単一の文字からなる文字列に変換するにはどうすればよいでしょうか?

chr(0xC0) eq 'À'保持します。を使用して、UTF-8 を使用してソース コードをエンコードしたことを Perl に伝えたことを覚えていますuse utf8;か? Perl に伝えなかった場合、Perl は実際に RHS で 2 文字の文字列を認識します。


あなたが追加した質問について:

encodingプラグマに問題があります。使用しないことをお勧めします。代わりに、

use open ':std', ':encoding(UTF-8)';

これで問題の 1 つが解決します。あなたが遭遇している他の問題は

chr(0x00C0) =~ /\w/

これは既知のバグであり、下位互換性のために意図的に壊れたままになっています。つまり、次のように言語のより新しいバージョンを要求しない限り:

use 5.014;    # use 5.012; *might* suffice.

5.8 までさかのぼって機能する回避策:

my $x = chr(0x00C0);
utf8::upgrade($x);
$x =~ /\w/
于 2012-09-06T00:15:15.640 に答える