web-dev-qa-db-ja.com

なぜ現代のPerlはデフォルトでUTF-8を避けるのですか?

Perlを使用して構築された最新のソリューションのほとんどが、デフォルトで TF-8 を有効にしないのはなぜかと思います。

コアPerlスクリプトには多くのレガシー問題があり、それが問題を引き起こす可能性があることを理解しています。しかし、私の観点から、21st 世紀、大きな新しいプロジェクト(または大きな展望を持つプロジェクト)は、最初からソフトウェアのUTF-8証明を行う必要があります。それでも私はそれが起こっているのを見ていません。たとえば、 Moose は厳密および警告を有効にしますが、 nicode は有効にしません。 Modern :: Perl は定型文も減らしますが、UTF-8の処理は行いません。

どうして? 2011年に現代のPerlプロジェクトでUTF-8を使用しない理由はありますか?


@tchristへのコメントが長すぎたので、ここに追加します。

私は自分自身を明らかにしなかったようです。いくつか追加してみましょう。

tchrist状況はかなり似ていますが、結論は完全に反対です。私は同意します、Unicodeの状況は複雑ですが、だからこそ、私たち(Perlユーザーとコーダー)は、UTF-8の取り扱いを現在のように簡単にするレイヤー(またはプラグマ)を必要とします。

tchristカバーする多くの側面を指摘し、私はそれらを数日または数週間読んで考えます。それでも、これは私のポイントではありません。 tchristは、「UTF-8を有効にする」単一の方法がないことを証明しようとします。私はそれについて議論するほど多くの知識を持っていません。だから、私は実例に固執しています。

Rakudo で遊んでみたところ、UTF-8がちょうどそこにありました必要に応じて。私は問題がなかった、それはちょうど働いた。より深いところに何らかの制限があるかもしれませんが、最初はテストしたすべてが期待どおりに機能しました。

それも現代のPerl 5の目標ではないでしょうか?さらに強調します。コアPerlのデフォルトの文字セットとしてUTF-8を提案するのではなく、それをトリガーする可能性を提案しますwith with snap開発者向けnew =プロジェクト。

別の例ですが、よりネガティブなトーンです。フレームワークは開発を容易にするはずです。数年前、私はWebフレームワークを試しましたが、「UTF-8を有効にする」ことがあまりにもあいまいだったため、それらを捨てました。 Unicodeサポートをフックする方法と場所を見つけられませんでした。時間がかかりすぎたため、古い方法を使用する方が簡単でした。今、私はここで Mason 2:と同じ問題に対処するための報奨金があるのを見ました:Mason2 UTF-8をきれいにする方法?。したがって、これはかなり新しいフレームワークですが、UTF-8で使用するには、内部の深い知識が必要です。それは大きな赤い看板のようなものです:やめて、私を使わないでください!

私はPerlが本当に好きです。しかし、Unicodeを扱うのは苦痛です。私はまだ壁に向かって走っている自分自身を見つけます。何らかの方法tchristが正しく、私の質問に答えます。新しいプロジェクトはPerl 5では複雑すぎるため、UTF-8を引き付けません。

553
w.k

Unicodeテキストの処理には2つの段階があります。 1つ目は「情報を失うことなく入力して出力する方法」です。二つ目は、 "私はどのように私は地元の言語の慣習に従ってテキストを扱うのですか"です。

tchristの投稿は両方をカバーしていますが、2番目の部分は彼の投稿のテキストの99%がどこから来ているかです。ほとんどのプログラムはI/Oを正しく処理しないため、正規化や照合順序について心配する前に、このことを理解することが重要です。

この記事はその最初の問題を解決することを目的としています

Perlにデータを読み込むとき、それがどんなエンコーディングであるかは気にしません。メモリを割り当て、バイトをそこに隠します。あなたがprint $strと言った場合、それはそれらのバイトをあなたの端末に書き出すだけです。おそらくそれはそこに書かれたものがすべてUTF-8であると仮定するように設定され、あなたのテキストが現れます。

素晴らしい。

それ以外は違います。データをテキストとして扱おうとすると、Something Badが起こっていることがわかります。 Perlがあなたの文字列についてどう思うか、そしてあなたが自分の文字列についてどう思うかは、lengthだけです。 Perl -E 'while(<>){ chomp; say length }'のようなワンライナーを書いて、文字化けとタイプすれば、あなたは12を得ます...正解ではありません、4。

Perlはあなたの文字列がテキストではないと仮定しているからです。それはあなたに正しい答えを与える前にそれがテキストであることをそれを言わなければなりません。

それは十分簡単です。 Encodeモジュールにはそれを実行する機能があります。一般的なエントリポイントはEncode::decode(またはもちろんuse Encode qw(decode))です。その関数は外界から文字列を取り(私たちは "オクテット"と呼ぶもの、 "8ビットバイト"と言うのは空想的です)、それをPerlが理解できるテキストに変換します。最初の引数は、 "UTF-8"、 "ASCII"、 "EUC-JP"のような文字エンコード名です。 2番目の引数は文字列です。戻り値はテキストを含むPerlのスカラです。

(エンコードにUTF-8を想定しているEncode::decode_utf8もあります。)

ワンライナーを書き直すと:

Perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

文字化けを入力して結果として "4"を得ます。成功。

それが、PerlのUnicode問題の99%に対する解決策です。

重要なのは、テキストがプログラムに入ったときはいつでも、それをデコードしなければならないということです。インターネットは文字を送信できません。ファイルは文字を格納できません。データベースに文字がありません。オクテットしかないので、Perlではオクテットを文字として扱うことはできません。 Encodeモジュールを使用して、エンコードされたオクテットをPerlの文字にデコードする必要があります。

問題のもう半分は、プログラムからデータを取り出すことです。それは簡単です。あなたはuse Encode qw(encode)を言って、あなたのデータのエンコーディングが何であるかを決め(UTF-8を理解する端末にはUTF-8、Windows上のファイルにはUTF-16など)、$dataを出力する代わりにencode($encoding, $data)の結果を出力します。 。

この操作はあなたのプログラムが操作するものであるPerlの文字を外の世界で使われることができるオクテットに変換します。インターネットや端末に文字を送信することができれば、はるかに簡単になりますが、できないのはオクテットだけです。そのため、文字をオクテットに変換する必要があります。それ以外の場合、結果は未定義です。

要約すると、すべての出力をエンコードし、すべての入力をデコードします。

それでは、これを少し難しくする3つの問題について説明します。一つは図書館です。彼らはテキストを正しく扱っていますか?答えは…彼らは試みます。 Webページをダウンロードすると、LWPは結果をテキストとして返します。その結果に対して正しいメソッドを呼び出すと、それは(そしてそれはcontentではなくdecoded_contentであることになります。これは、サーバーから取得したオクテットストリームにすぎません。)データベースドライバは不安定かもしれません。 DBD :: SQLiteをPerlだけで使用した場合は問題ありませんが、他のツールがデータベースにUTF-8以外のエンコーディングとしてテキストを格納していると...正しく処理されません。正しく扱うコードを書くまで。

データの出力は通常は簡単ですが、「ワイド文字の活字」と表示されている場合は、どこかでエンコードがめちゃくちゃになっていることがわかります。その警告は、「ちょっと、あなたはPerlの文字を外の世界に漏らそうとしているので、意味をなさない」という意味です。あなたのプログラムは動作するように見えます(もう片方の端は通常生のPerl文字を正しく処理するので)が、それは非常に壊れていていつでも動作をやめることができます。明示的なEncode::encodeで修正してください。

2番目の問題はUTF-8でエンコードされたソースコードです。各ファイルの先頭にuse utf8を付けていない限り、PerlはあなたのソースコードがUTF-8であると想定しません。これは、あなたがmy $var = 'ほげ'のような何かを言う度に、あなたはあなたのプログラムにゴミを注入していることを意味しています。あなたは "use utf8"をする必要はありませんが、もしそうでなければ、あなたはあなたのプログラムの中でASCII以外の文字を使わないでください

3番目の問題は、Perlが過去をどのように処理するかです。ずっと前に、Unicodeのようなものはありませんでした、そしてPerlはすべてがLatin-1テキストまたはバイナリであると仮定しました。そのため、データがプログラムに入ってきてテキストとして扱うようになると、Perlは各オクテットをLatin-1文字として扱います。そのため、 "文字化け"の長さを尋ねると12になりました。Perlは、Latin-1文字列 "æååã"(12文字、うち一部は印刷されない文字列)を操作していると見なしました。

これは「暗黙のアップグレード」と呼ばれ、実行するのは完全に合理的なことですが、テキストがLatin-1ではない場合には必要なことではありません。そういうわけでそれは明示的に入力をデコードすることが重要である理由です:あなたがそれをしないならPerlはそうするでしょう、そしてそれはそれを間違って行うかもしれません。

データの半分が適切な文字列で、一部はまだバイナリであるという問題に遭遇します。 Perlは、それでもLatin-1テキストのようにバイナリの部分を解釈し、それを正しい文字データと結合します。これはあなたのキャラクターを正しく扱うことがあなたのプログラムを壊したように見えますが、実際には、あなたはそれを十分に修正していません。

ここに例があります:あなたはUTF-8でエンコードされたテキストファイルを読むプログラムを持っていて、あなたは各行にUnicodeのPILE OF POOを付けてそれをプリントアウトします。あなたはそれを書きます:

while(<>){
    chomp;
    say "$_ ????";
}

そして、次のように、UTF-8でエンコードされたデータで実行します。

Perl poo.pl input-data.txt

各行の終わりにうんちを入れてUTF-8データを出力します。完璧です、私のプログラムはうまくいきます!

しかし、いいえ、バイナリ連結をしているだけです。ファイルからオクテットを読み取り、chompで\nを削除してから、PILE OF POO文字のUTF-8表現のバイトを追跡します。ファイルからデータをデコードして出力をエンコードするようにプログラムを修正すると、うんちの代わりにゴミ( "Ž©")が出ることに気づくでしょう。これにより、入力ファイルをデコードするのは間違ったことだと信じるようになります。そうではありません。

問題は、うんちがlatin-1として暗黙のうちにアップグレードされていることです。バイナリではなくリテラルテキストを作成するためにuse utf8を使用した場合、それは再び機能します。

(それは、Unicodeを使って人々を助けるときに私たちが見ている一番の問題です。彼らは部分的に正しく、プログラムを壊しました。それは未定義の結果に対して悲しいことです。プログラムにエンコード/デコード文を追加していてそれが壊れたとしても、最初からUnicodeを念頭に置いて設計すると、次のようになります。はるかに簡単!

PerlとUnicodeについて知っておく必要があるのはこれだけです。 Perlにあなたのデータが何であるかを伝えれば、それはすべての一般的なプログラミング言語の中で最高のUnicodeサポートを持っています。あなたがそれがどんな種類のテキストをあなたがそれを供給しているかを魔法のように知っているとあなたが思うならば、しかし、あなたは取り返しのつかないほどあなたのデータを捨てるつもりです。あなたのプログラムが今日のあなたのUTF-8端末上で動作するからといって、それが明日UTF-16でエンコードされたファイル上で動作することを意味するわけではありません。だから今安全にして、そしてあなた自身のあなたのユーザーのデータを捨てることの頭痛を救いなさい!

Unicode処理の簡単な部分は、出力のエンコードと入力のデコードです。難しいのは、入力と出力をすべて見つけて、それがどのエンコーディングかを判断することです。しかし、それがあなたが大金を手に入れる理由です:)

96
jrockway

私たちは皆、それが多くの理由から難しい問題であることに同意していますが、それがまさに誰にとっても簡単にすることを試みる理由です。

CPANに関する最近のモジュール、 utf8 :: all があります。これは、「Unicodeを有効にします。全部」です。

すでに指摘したように、システム全体(外部プログラム、外部Web要求など)にも魔法のようにUnicodeを使用させることはできませんが、共通の問題をより簡単にする賢明なツールを作るために協力できます。それが私たちがプログラマーである理由です。

Utf8 :: allであなたが思うべきことをしないのなら、それを改善してより良いものにしましょう。あるいは一緒に人々のさまざまなニーズにできるだけ合うことができる追加のツールを作りましょう。

`

47
Randy Stauner

私はあなたがUnicodeとそのPerlとの関係を誤解していると思います。どのような方法でデータを保存するか、Unicode、 ISO-8859-1 、または他の多くのことを問わず、プログラムはそれをどのように解釈するかを知っておく必要があります入力として取得し(デコード)、出力したい情報を表す方法(エンコード)。その解釈を誤ると、データが文字化けします。あなたのプログラムの中には、どのように振る舞うべきかを教えるための魔法のようなデフォルト設定はありません。

あなたはそれが難しいと思います、おそらくあなたはすべてがASCIIであることに慣れているからです。あなたが考えているべきであるすべてはプログラミング言語およびそれが相互に作用しなければならなかったことすべてによって単に無視された。すべてがUTF-8以外のものを何も使用せず、あなたに選択の余地がなかったら、UTF-8も同じくらい簡単でしょう。しかし、すべてがUTF-8を使用しているわけではありません。たとえば、入力ハンドルが実際にそうでない限りUTF-8オクテットになっているとは思わないでください。また、出力ハンドルがUTF-8を処理できる場合は、出力ハンドルをUTF-8にしたくないとします。 。 Perlはそれらのことを知る方法がありません。だからこそあなたはプログラマーです。

私はPerl 5のUnicodeが複雑すぎるとは思わない。私はそれが怖いと思い、人々はそれを避けます。違いがあります。そのために、私はUnicodeを Perlの学習、第6版にはたくさんのUnicodeのものがあります 効果的なPerlプログラミング。あなたは、Unicodeとそれがどのように機能するかを学び理解するために時間を費やさなければなりません。そうでなければそれを効果的に使うことができないでしょう。

34
brian d foy

このスレッドを読んでいる間、私は人々が " UTF-8 "を " の同義語として使用しているという印象をよく持ちます)Unicode ") ASCIIコードとUnicodeのさまざまな "エンコーディング"との関係を拡大したUnicodeの "コードポイント"と区別してください。そしてそれらのいくつかがあり、そのうちUTF-8、 UTF-16UTF-32 は現在のもので、さらにいくつかは時代遅れです。

UTF-8(および他のすべてのエンコーディング)が存在し、入力または出力でのみ意味があります。内部的には、Perl 5.8.1以降、すべての文字列はUnicodeの「コードポイント」として保持されています。確かに、あなたは以前に賞賛されるようにいくつかの機能を有効にしなければなりません。

28
MeirG

世の中には本当に恐ろしい量の古代コードがあり、その多くは一般的なCPANモジュールの形をしています。 Unicodeの影響を受ける可能性のある外部モジュールを使用する場合、Unicodeの有効化にかなり注意する必要があることに気付きました。 iTiVo は、トランスコードの問題により、7ビットASCII以外のものではひどく失敗します)。

10
geekosaur

Unicode文字列機能を有効にする必要があります。v5.14を使用している場合はこれがデフォルトです。

あなたは本当にUnicode識別子espを使うべきではありません。 utf8を介した外部コードはPerl 5では安全ではないため、cperlだけがその権利を得ました。例えば参照。 http://Perl11.org/blog/unicode-identifiers.html

あなたのファイルハンドル/ストリームのためのutf8に関して:あなたはあなた自身であなたの外部データのエンコーディングを決める必要があります。ライブラリはそれを知ることができません、そしてlibcさえutf8をサポートしないので、正しいutf8データはまれです。もっとwtf8、utf8の窓の異常があります。

ところで:Mooseは実際には "Modern Perl"ではありません。名前をハイジャックしただけです。 MooseはLarry Wall風のポストモダンPerlとBjarne Stroustrup風のものがすべて混在した完璧なものです。変数名、恐ろしいフィールドの構文、および適切な実装よりも10倍遅い非常に未熟な単純な実装に文字列を使用する。 cperlとPerl6は真の現代的なperlです。形式は機能に従います、そして実装は縮小され最適化されます。

1
rurban