実際、PerlにはUTF-8の実装が2つありました。 最初のものはPerl 5.6で登場しましたが、かなり粗野で不便でした。 Perl 5.8以降、Unicodeメカニズムは根本的に改訂され、CPANのモジュールには、インタープリターのバージョンに関する面白いチェックがいっぱいです。 以下に記述されているものはすべて、正確にこの2番目の実装に関連しています。
長所と短所
まだエンコーディング、冷静に開発された単一言語アプリケーションについて考えていなくて、同じやり方で続けるつもりなら、ほぼ確実にユニコードは必要ありません。 いずれの場合も、シングルバイトエンコーディングのデータはよりコンパクトであり、より高速に処理され、簡単かつ快適に処理できます。
データの次の部分がアプリケーションに送信される形式がわからない場合、または国際プロジェクトを開発している場合は、おそらくUTF-8が必要になります。 実際、あなたのサイトが英語であっても、名前にウムラウトが付いているドイツ人、または中王国の居住者でさえ登録することができます。 データベースでその後何が起こるかを考えない最も簡単な方法(お気に入りのlatin-1で中国語の名前を表示する方法について)は、多くの言語をサポートするエンコーディングで作業することです。
また、Perl UTFを知ることができないもう1つのケースは、この形式で動作するサードパーティコンポーネントとの統合です。 たとえば、
XML::LibXML
は、この形式のXMLファイルの解析結果を返します。
perlの方法
おそらく、鉱夫たちは次のようなことを主張しました。変数にバイトチェーンを格納したので、そこに文字を格納する方法を学ぶ必要があります。 UTF-8の文字長は一貫性がなく、1バイト以上になる場合があります。 文字列を操作するためのレギュラーと関数(
length
、
substr
)の動作が異なる場合、彼らは感謝を言いません。 したがって、2つのタイプの文字列を作成する必要があります-古いパターンで動作するためのbytesと、新しいパターンで動作するためのcharactersです。 どうやってやるの? そして、スカラーに隠しフラグを導入しましょう。 フラグが設定されている場合、文字列は論理文字( Perl内部形式と呼びましょう)で構成されていると認識されます。そうでない場合は、バイトから認識されます。
2つの同一のUnicode変数を使用して、そのうちの1つのフラグをドロップするだけの場合、変数は真珠によって異なる方法で処理されます(たとえば、長さが異なる可能性が高い)。 ただし、データ自体は同時に変更されません-これは、たとえば、両方の変数がファイルまたは画面に表示されている場合に確認できます。
Perlの用語ではUTF-8文字はしばしばワイド文字と呼ばれることに言及する価値があります。 これらの単語で警告に出くわすと、ユニコード文字列になります。
PerlでUnicodeデータを操作するためのオプションがいくつかあります。 主なものは次のとおりです。
- 文字列内のユニコード文字の強制的な表示-
\x{0100}
形式の構築。 -
Encode
モジュールまたはutf8
パッケージの関数を使用した文字列の手動再utf8
。 - enable pragma
use utf8
フラグは、コード内で検出されたすべての定数に対して発生します。 - IO層を示すI / O記述子からの読み取り
:encoding
または:utf8
すべてのデータは自動的に内部形式に変換されます。
Encode
モジュール
このモジュールはPerl 5.8に含まれているため、Unicodeだけでなく他のエンコード変換にも使用するのが理にかなっています。 モジュールの操作はそれほど複雑ではありません。 唯一の問題は、
encode
機能と
decode
機能を混同しないことを学習
decode
ことです:-)。 それらは同じインターフェースを持ち、命名ロジックは私たちが望むほど明白ではありません。 Unicodeフラグのある文字列の形式は内部形式と見なされるため、任意のエンコード(フラグのないUTF-8を含む)からデータをデコードする必要があります。逆も同様です。特定の外部エンコードにデータを転送する場合は、内部形式からエンコードする必要があります彼女。 次のようになります。
$bytes = encode('cp1251', $string); # cp1251
$string = decode('cp1251', $bytes); #
あるエンコードから別のエンコードにすべての文字を失うことなく追跡できるわけではないため、問題が発生した場合の動作を決定する3番目のパラメーターもあります。
Encode
モジュールのドキュメントでそれについて読むことができます 。そこにはセクション全体がこれに
Encode
られています。
変数にUTF-8のバイトが含まれていることが確実な場合は、
_utf8_on
再コーディングおよびチェックする必要なく、変数のフラグを立てることができます。 関数
is_utf8
は、行にフラグがあるかどうか(およびそこにあるデータの有効性を確認するかどうか)を判断するのに役立ちます。 ご
_utf8_off
、フラグは
_utf8_off
によってリセットされます。 唯一の「しかし」-これらの関数はINTERNALとしてマークされており、不変性に頼るべきではありません。
Perl 5.8.1以降、
Encode
モジュールの関数の一部が
utf8::
名前空間で使用可能になりました-これらは
is_utf8
、
encode
、
decode
関数
is_utf8
。 後者の2つは、結果を返す代わりに渡された変数の値を変更し、エンコードを必要としないという点で
Encode
モジュールの同義語と異なります(フラグを立てずにUTF-8データを処理することが理解されています)。 これらの関数はすべてインタープリターに組み込まれているため、これらにアクセス
use utf8
を
use utf8
必要はありません-さらに、これは追加の効果をもたらす可能性があります(少し後で)。
use utf8;
use utf8
は、その操作のゾーンに書き込まれ、非ASCII文字を持つすべての定数と正規表現をUnicodeとして扱い、内部形式に自動的に変換する必要があることをインタープリターに伝えます。 プラグマをキャンセルするには、通常どおり、
no utf8
コンストラクトが使用されます。
プラグマ
use bytes
するという意味では、逆もあり
use bytes
。この領域では、UTF-8フラグを持つデータでさえ、バイトで構成されるものとして扱われます。
PerlIO
Perl IO Layersテーマは、原則として別の記事に値します。 アイデアは、しばらくの間、古き良き
open
関数が3つの引数の構文を取得したということです。
open $fh, $mode, $filename
$mode
のタイプ
'>'
および
'<'
の標準値に加えて、ファイルのエンコードを指定することもできます。 この場合、ダウンロードされたデータは自動的に内部Perl形式に変換されます。
open $fh, "<:encoding(cp1251)", $filename
UTF-8のデータを含むファイルについて話している場合は、コードを少し単純化できます。
open $fh, "<:utf8", $filename
もちろん、これらの修飾子を使用してファイルを変更できます-効果は逆になります。
ところで、Perlには、
-C
コマンドラインスイッチを使用して、I / Oストリームを一度だけUnicodeにする機能があります。 詳細は、いつものようにperldocで見ることができます。
すくい
もちろんそうです。
最初に、一部の関数は、定義上、文字ではなくバイトで動作し、内部表現の行は喉を横切って上昇します。 これらの関数には、
Digest::MD5
モジュールで頻繁に使用される関数が含まれます。 そのため、指定された例は
Wide character in subroutine entry at test.pl line 3.
エラー
Wide character in subroutine entry at test.pl line 3.
落ちます。
use Digest::MD5 'md5_hex';
print md5_hex("\x{400}");
第二に、データは常にプログラムがそれを見ると期待する形式になっているわけではありません。 たとえば、有効なUTF-8が常にHTMLフォームハンドラーに来ることを期待するのは単純です。 ソースに対する過度の信頼の結果は、データの破損から始まり、別のエンコーディングへのトランスコード(たとえば、電子メールの生成時)での致命的なエラーで終わる、非常に多様なものになります。
最後に、最も一般的で興味深い問題は、2つの文字列を連結しようとしたときに発生し、そのうちの1つだけが内部の真珠の形式で保存されます。 このようなファイル(UTF-8で記録)があるとします:
use Encode;
$a = decode('utf8', " "); #
$b = " "; # 15
$c = $a.$b;
最後の行では、Perlは文字列を共通の
$b
をバイト文字列として認識しているため、この文字列の各バイトはUTF-8でエンコードされています。 結果は、この混乱のようなものです(ちなみに、フラグが立てられています):
$c = " на Хабре"
グリッチは、ユニコード固有のワニを通して肉眼ではっきりと見える-あなたはそれを何かと混同することはできません。
おわりに
この記事では多くの微妙な点が未解決のままでした。
Encode
モジュールの多くのユーティリティ
utf8
残っていました。 UTF-8の観点からは無効な文字に敏感な内部形式のバリエーションについて言及する場所はありませんでした。 正規表現に関連する質問は完全に省略されています。 このトピックを最後まで掘り下げたい場合は、マニュアルに注意してください。
- perldoc utf8 ;
- perldoc Encode ;
- perldoc perluniintro ;
- perldoc perlunitut ;
- perldoc perlunifaq ;
- perldoc perlunicode
UPD:コード署名habrayuzerは、同じトピックに関する彼自身の開発へのリンクを送信しました。