UTF-16は有害と見なされるべきですか?


432

「おそらく最も人気のあるエンコーディングの1つであるUTF-16は有害と見なされるべきですか?」

なぜこの質問をするのですか?

UTF-16が実際に可変長エンコードであるという事実を知っているプログラマーは何人いますか?これにより、サロゲートペアとして表されるコードポイントがあり、複数の要素を取ることができます。

知っている; Javaの文字列、C#の文字列、Win32 API、Qt GUIライブラリ、ICU Unicodeライブラリなど、多くのアプリケーション、フレームワーク、およびAPIはUTF-16を使用します。しかし、すべての処理には、処理に多くの基本的なバグBMP以外の文字(2つのUTF-16要素を使用してエンコードする必要のある文字)。

たとえば、次の文字のいずれかを編集してみてください。

インストールしたフォントによっては、見逃す場合があります。これらのキャラクターはすべてBMP(Basic Multilingual Plane)の外部にあります。これらの文字が表示されない場合は、Unicode Character referenceでそれらを確認してみてください

たとえば、Windowsでこれらの文字を含むファイル名を作成してみてください。「バックスペース」でこれらの文字を削除して、UTF-16を使用するさまざまなアプリケーションでの動作を確認してください。私はいくつかのテストを行いましたが、結果は非常に悪いです:

  • Operaでの編集に問題があります(バックスペースで2回押す必要がある削除)
  • メモ帳はそれらを正しく処理できません(バックスペースで必要な2つのプレスを削除します)
  • ウィンドウダイアログでのファイル名の編集が壊れている(バックスペースで2回押す必要がある削除)
  • すべてのQT3アプリケーションはそれらを処理できません-1 つのシンボルではなく2つの空の正方形を表示します。
  • u'X'!=unicode('X','utf-16')XがBMPの外の文字である場合、一部のプラットフォームで直接使用すると、Pythonはそのような文字を誤ってエンコードします。
  • Python 2.5 unicodedataは、PythonがUTF-16 Unicode文字列でコンパイルされている場合、そのような文字のプロパティを取得できません。
  • StackOverflowは、Unicode文字として直接編集された場合、これらの文字をテキストから削除するようです(これらの文字はHTML Unicodeエスケープを使用して表示されます)。
  • WinForms TextBoxは、MaxLengthで制限されている場合、無効な文字列を生成する場合があります

このようなバグは、UTF-16を使用する多くのアプリケーションで非常に簡単に見つけることができるようです。

だから...あなたはUTF-16は有害と見なされるべきだと思いますか?


64
本当に正しくありません。「שָׁ」、「ָ」、「ׁ」、vovelsで構成される複合文字「שָׁ」を書くと、それらのそれぞれの削除は論理的であり、「バックスペース」を押し、「del」を押すと、vovelsを含むすべての文字を削除します。しかし、違法なテキスト状態(違法なコードポイント)を生成することはありません。したがって、バックスペースを押して不正なテキストを取得する状況は正しくありません。

41
CiscoIPPhone:バグが「多くの異なる人々によって数回報告された」場合、数年後、開発者が開発者のブログに「信じるかどうか、動作は主に意図的です!」穏やかに)私はそれがおそらくこれまでになされた最高の設計決定ではないと思う傾向があります。:-)意図的だからといって、それがバグではないわけではありません。

145
素晴らしい投稿。UTF-16は確かに「両方の世界で最悪」です。UTF8は可変長で、すべてのUnicodeをカバーし、生のコードポイントとの間で変換アルゴリズムを必要とし、ASCIIに制限され、エンディアンネスの問題はありません。UTF32は固定長であり、変換を必要としませんが、より多くのスペースを取り、エンディアンネスの問題があります。これまでのところ、内部的にはUTF32を使用し、シリアル化にはUTF8を使用できます。しかし、UTF16には利点がありません。エンディアンに依存し、可変長であり、多くのスペースを必要とし、ASCII互換ではありません。UTF16を適切に処理するために必要な作業は、UTF8により適切に費やすことができます。
ケレックSB

26
@Ian:UTF-8にはUTF-8 と同じ注意事項はありません。UTF-8ではサロゲートを使用できません。UTF-8はそうではないものに見せかけているわけではありませんが、UTF-16を使用するほとんどのプログラマーは間違った使い方をしています。知っている。私はそれらを何度も何度も見ました。
tchrist

18
また、UTF-8は、誰もが可変幅エンコーディングとして扱うため、問題はありません。UTF-16に問題がある理由は、誰もがUTF-16を固定幅エンコーディングのように扱うためです。
クリストファーハマーストローム

回答:


340

これは古い答えです。最新の更新については、UTF-8 Everywhere
参照してください。

意見:はい、UTF-16は有害と見なされるべきです。それが存在するまさにその理由は、以前はワイド文字が現在のUCS-4であるという誤った信念があったためです。

UTF-8の "anglo-centrism"にもかかわらず、テキストの唯一の有用なエンコーディングと見なされるべきです。プログラム、Webページ、XMLファイル、OSファイル名、その他のコンピューター間のテキストインターフェイスのソースコードが存在することはなかったと主張することができます。しかし、そうするとき、テキストは人間の読者だけのものではありません。

一方、UTF-8のオーバーヘッドは、大きな利点がある一方で、支払う代価はわずかです。で文字列を渡すだけの非認識コードとの互換性などの利点char*。これは素晴らしいことです。UTF-8よりもUTF-16の方が短い文字はほとんどありません。

私は他のすべてのエンコーディングが最終的に死ぬと信じています。これには、MS-Windows、Java、ICU、Pythonがお気に入りとしての使用を停止することが含まれます。長い研究と議論の後、私の会社の開発規約では OS API呼び出し以外の場所でUTF-16を使用することを禁止しています。これは、アプリケーションのパフォーマンスとWindowsを使用しているという事実にもかかわらずです。変換関数は、always-assumed-UTF8 std::stringをネイティブのUTF-16 に変換するために開発されましたが、Windows自体は適切にサポートしていません

必要な場所で必要なものを使用する」と言う人には、どこでも同じエンコーディングを使用することには大きな利点があり、そうしない十分な理由はないと思います。特に、wchar_tC ++への追加は間違いであり、C ++ 0xへのUnicodeの追加も間違いだと思います。ただし、STL実装に要求する必要があるのは、すべてstd::stringまたはchar*パラメーターがユニコード互換と見なされることです。

また、「あなたが欲しいものを使う」というアプローチにも反対です。私にはそのような自由の理由はありません。テキストの主題については十分な混乱があり、このすべての壊れたソフトウェアに帰着します。上記で述べたように、私はプログラマーがUTF-8の1つの適切な方法として最終的に合意に達する必要があると確信しています。(私は非アスキー語圏の国から来て、Windowsで育ったので、宗教的根拠に基づいてUTF-16を攻撃することが最後に期待されるでしょう)。

Windowsでのテキストの実行方法、およびコンパイル時にチェックされるユニコードの正確性、使いやすさ、コードのマルチプラットフォーム性の向上のために他の人に推奨することについて、さらに情報を共有したいと思います。この提案は、WindowsでUnicodeを使用する適切な方法として通常推奨されるものとは大きく異なります。しかし、これらの推奨事項を徹底的に調査した結果、同じ結論が得られました。だからここに行きます:

  • UTF-16を受け入れるAPIを隣接する場所以外で使用しwchar_tたりstd::wstring、使用したりしないでください。
  • 使用しないでください_T("")またはL""UTF-16のリテラル(これらは、IMO UTF-16廃止の一環として、標準から取り出す必要があります)。
  • 敏感なタイプ、機能またはそれらの誘導体を使用しないでください_UNICODEなど、定数をLPTSTRCreateWindow()
  • それでも、_UNICODE常に定義され、char*WinAPIに文字列を渡してサイレントコンパイルされないようにします。
  • std::stringsそしてchar*、プログラム内のどこでもUTF-8と見なされます(特に指定がない場合)
  • すべての文字列はstd::string、char *または文字列リテラルをに渡すことができますがconvert(const std::string &)
  • widechars(LPWSTR)を受け入れるWin32関数のみを使用してください。LPTSTRまたはを受け入れるものLPSTR。この方法でパラメーターを渡します。

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())
    

    (このポリシーは以下の変換関数を使用します。)

  • MFC文字列の場合:

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
    
  • Windowsでのファイル、ファイル名、fstreamの操作:

    • ファミリに引数を渡しstd::stringたり、const char*ファイル名を付けたりしないでくださいfstream。MSVC STLはUTF-8引数をサポートしていませんが、次のように使用する必要がある非標準の拡張子があります。
    • 変換std::stringに引数をstd::wstring持ちますUtils::Convert

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |
                        std::ios_base::binary);
      

      MSVCの姿勢がfstream変化した場合、変換を手動で削除する必要があります。

    • このコードはマルチプラットフォームではないため、将来的には手動で変更する必要があります
    • 詳細については、fstreamUnicodeの調査/議論ケース4215を参照してください。
    • 非UTF8コンテンツのテキスト出力ファイルを作成しない
    • fopen()RAII / OODの理由で使用しないでください。必要に応じて、_wfopen()上記のWinAPI規則を使用します。

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
{
    // Ask me for implementation..
    ...
}

// Interface to MFC
std::string convert(const CString &mfcString)
{
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
#else
    return mfcString.GetString();   // This branch is deprecated.
#endif
}

CString convert(const std::string &s)
{
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
#else
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
#endif
}

39
同意できません。多くのアジア言語のutf8に対するutf16の利点は、あなたが作るポイントを完全に支配します。日本人、タイ人、中国人などがこのエンコーディングを放棄することを期待するのは単純です。文字セット間の問題のある衝突は、違いを除いて、文字セットがほとんど似ているように見える場合です。標準化することをお勧めします:固定7ビット:iso-irv-170; 8ビット変数:utf8; 16ビット変数:utf16; 32ビット修正:ucs4。

82
@Charles:ご意見ありがとうございます。確かに、一部のBMP文字はUTF-16よりもUTF-8で長いです。しかし、問題に直面しましょう。問題は、BMPの漢字のバイト単位ではなく、ソフトウェア設計の複雑さです。とにかく、中国のプログラマーが可変長文字用に設計しなければならない場合、システム内の他の変数と比較して、UTF-8の支払いはまだ小さいようです。スペースが非常に重要な場合、圧縮アルゴリズムとしてUTF-16を使用する場合がありますが、それでもLZには一致せず、LZまたは他の汎用圧縮の両方でほぼ同じサイズとエントロピーがかかります。

32
私が基本的に言っているのは、既存のchar *プログラムとも互換性があり、すべてで最も人気のあるOneエンコーディングを使用することによる単純化は想像できないことです。古き良き「平文」時代のようです。名前の付いたファイルを開きたいですか?開発者は、UTF-16を非常に特殊な厳しい最適化の場合に限定することをお勧めします。この場合、ほんのわずかなパフォーマンスが数ヶ月の作業に値します。

17
Linuxには、UTF-8を内部で使用することを選択するときに、Unixとの互換性という特定の要件があります。Windowsはそれを必要としなかったので、開発者がUnicodeを実装したときに、テキストを処理するほぼすべての関数のUCS-2バージョンを追加し、マルチバイト関数を単純にUCS-2に変換して他の関数を呼び出しました。後でUCS-2をUTF-16に置き換えます。一方、Linuxは8ビットエンコーディングを維持し、UTF-8を使用しました。これは、その場合に適切な選択だからです。
ミルチャチレア

34
@Pavel Radzivilovsky:ところで、「他のすべてのエンコーディングは最終的に死ぬと信じています。これには、MS-Windows、Java、ICU、pythonがお気に入りとしての使用を停止することが含まれます。」そして「特に、私はC ++へのwchar_tを追加することが間違いだったと思うし、そうC ++牛へのUnicodeの追加があります。」非常に素朴であるか、非常にvery慢です。これは、自宅でLinuxを使用してコーディングしていて、UTF-8文字に満足している人から来ています。率直に言って、それは起こりません
パーセバル

157

Unicodeコードポイントは文字ではありません! 場合によっては、グリフ(視覚形式)でさえありません。

いくつかの例:

  • 「ⅲ」のようなローマ数字のコードポイント。(「iii」のように見える単一の文字。)
  • 「á」のようなアクセント付き文字。単一の結合文字「\ u00e1」または発音区別記号「\ u0061 \ u0301」で区切られた文字として表すことができます。
  • ギリシャ語の小文字シグマのような文字。単語の位置の中央( "σ")と末尾( "ς")の形式は異なりますが、検索の同義語と見なされる必要があります。
  • Unicode随意ハイフンU + 00AD。コンテキストに応じて視覚的に表示される場合とされない場合があり、セマンティック検索では無視されます。

Unicodeを正しく編集する唯一の方法は、専門家が作成したライブラリ使用する、専門家になって自分で作成することです。コードポイントを数えるだけなら、あなたは罪の状態に生きています。


19
この。非常にこれ。UTF-16は問題を引き起こす可能性がありますが、UTF-32全体を使用しても問題が発生する可能性があります。
bcat

11
キャラクターとは?コードポイントを文字として定義し、ほとんど問題なく取得できます。あなたがユーザーに見えるグリフを意味するなら、それは別のものです。
tchrist

7
@tchristは、スペースを割り当てることでその定義は問題ないことを確信していますが、他には何かありますか?そんなにない。結合文字を単独の文字として処理する場合(つまり、削除または「最初のN文字を取得する」操作の場合)、奇妙で間違った動作になります。コードポイントが少なくとも別のコードポイントと組み合わされた場合にのみ意味を持つ場合、賢明な方法でそれ自体を処理することはできません。
Voo

6
@Pacerier、これはパーティーに遅れていますが、私はそれについてコメントしなければなりません。一部の言語には、発音区別記号の潜在的な組み合わせの非常に大きなセットがあります(ベトナム語、つまりmệtcfを参照)。分音記号ごとに1文字ではなく組み合わせを使用すると非常に便利です。
asthasr

21
用語に関する小さな注記:コードポイント Unicode文字に対応します。ここでダニエルが話しているのは、ユーザーが認識する文字です。これはユニコード書記素クラスターに
クリストフ

54

使用するUnicode変換フォーム(UTF)には、簡単な経験則があります。-ストレージと通信用のutf-8-データ処理用のutf-16-使用するプラットフォームAPIのほとんどがutf-32の場合utf-32(UNIXの世界では一般的)。

現在、ほとんどのシステムはutf-16(Windows、Mac OS、Java、.NET、ICU、Qt)を使用しています。このドキュメントも参照してください:http : //unicode.org/notes/tn12/

「有害なものとしてのUTF-16」に戻って、私は言うだろう:間違いなくそうだ。

サロゲート(Unicodeを可変長エンコーディングに変換すると考えている)を恐れる人は、文字とUnicodeコードポイント間のマッピングを非常に複雑にする他の(かなり大きい)複雑さを理解していません:文字、合字、バリエーションセレクターの組み合わせ、制御文字など

このシリーズhttp://www.siao2.com/2009/06/29/9800913.aspxを読んで、UTF-16が簡単な問題になる方法をご覧ください


26
UNIXの世界でUTF-32が一般的である例をいくつか追加してください!
maxschlepzig

48
いいえ、データ処理にUTF-16を使用する必要はありません。それはお尻の痛みです。UTF-8の欠点はすべてありますが、利点はありません。UTF-8とUTF-32の両方は、以前はMrs UTF-16として知られていた悪名のハックよりも明らかに優れています。
tchrist

34
私は昨日、Java equalsIgnoreCaseがUTF-8またはUTF-32のいずれかを使用していた場合には存在しなかった、JavaコアStringクラスのメソッド(文字列クラスの他のメソッド)にバグを見つけました。UTF-16を使用するコードには、これらの眠っている爆弾が何百万もあり、私はうんざりしています。UTF-16は悪意のあるpoであり、ソフトウェアに潜むバグを永遠に悩ませます。それは明らかに有害であり、廃止され禁止されるべきです。
tchrist

7
@tchristうわー、非サロゲートを意識した関数(何もなかったときに書かれていて、おそらく適応することをおそらく不可能にするような方法で文書化されているため-。古いコードポイントマップを使用したUTF-32関数では、これをうまく処理できないことをご存知ですか?また、Java API全体はサロゲートを特にうまく処理せず、ユニコードに関するより複雑な点もまったく処理しません-後で使用されるエンコーディングはまったく問題になりません。
Voo

8
-1:.Substring(1).NET の無条件は、すべての非BMP Unicodeのサポートを破るような些細な例です。UTF-16を使用するすべてにこの問題があります。固定幅のエンコードとして扱うのは簡単すぎるため、問題が発生することはほとんどありません。ユニコードをサポートしたい場合、それは積極的に有害なエンコーディングになります。
ローマンスターコフ

43

そのとおり。

どうして?それはコードの行使に関係しています

Tom Christiansenによる大規模なコーパスのこれらのコードポイント使用統計を見ると、非BMPコードポイントよりも大きければトランス8ビットBMPコードポイントが数桁使用されていることがわかります。

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE

 544 U+01D49E ‹𝒞›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL C
 450 U+01D4AF ‹𝒯›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL T
 385 U+01D4AE ‹𝒮›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL S
 292 U+01D49F ‹𝒟›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL D
 285 U+01D4B3 ‹𝒳›  GC=Lu    MATHEMATICAL SCRIPT CAPITAL X

「テストされていないコードは壊れたコードです」というTDDの原則を取り、「実行されていないコードは壊れたコード」と言い換え、プログラマーが非BMPコードポイントに対処しなければならない頻度を考えます。

UTF-16を可変幅エンコーディングとして処理しないことに関連するバグは、UTF-8の同等のバグよりも気付かれることはほとんどありません。プログラミング言語の中には、UCS-2の代わりにUTF-16を提供することを保証しないものもあります。また、一部のいわゆる高レベルプログラミング言語は、コードポイントではなくコードユニットへのアクセスを提供します(Cでさえ、wchar_t一部のプラットフォームが何をするかに関係なく、を使用する場合のコードポイント)。


16
「UTF-16を可変幅エンコーディングとして処理しないことに関連するバグは、UTF-8の同等のバグよりも気付かない可能性がはるかに高くなります。」これが問題の核心であり、正しい答えです。
ショーンマクミラン

3
正確に。UTF-8処理が中断された場合、すぐに明らかになります。UTF-8の処理が中断されている場合は、珍しい漢字または数学記号を入れた場合にのみ気付くでしょう。
機械式カタツムリ

1
非常に真実ですが、一方で、あまり頻繁ではないケースでバグを見つけるために運に頼る必要がある場合の単体テストは何ですか?
ムシフィル14年

@musiphil:それで、非BMPキャラクターのユニットテストを最後に作成したのはいつですか?
ninjalj

1
私の以前の声明を詳しく説明すると、UTF-8を使用している場合でも、いくつかの実際の例を参照しただけですべてのケースをカバーしたとは限りません。UTF-16でも同じです。コードが非サロゲートとサロゲートの両方で機能するかどうかをテストする必要があります。(UTF-8には少なくとも4つの主要なケースがあり、UTF-16には2つのケースしかないと主張する人もいます。)
musiphil 14年

40

UTF-16が有害であると考えられるかもしれないということは、Unicodeをより深く理解する必要があると言うことをお勧めします。

私は主観的な質問について私の意見を述べたことに落胆しているので、詳しく説明させてください。UTF-16についてあなたを悩ませているのは正確には何ですか?すべてがUTF-8でエンコードされている場合はどうでしょうか?UTF-7?または、UCS-4はどうですか?もちろん、特定のアプリケーションは、単一の文字コードをすべて処理するようには設計されていませんが、特に今日のグローバル情報ドメインでは、国境を越えた通信に必要です。

しかし、実際には、UTF-16が混乱したり、不適切に実装されたりする可能性があるため(Unicodeは間違いなくそうであるため)、UTF-16が有害であると考えられる場合、文字エンコードのどの方法が無害と見なされますか?

編集:明確にするために:なぜ標準の不適切な実装を標準自体の品質の反映と考えるのですか?他の人が後で指摘しているように、アプリケーションがツールを不適切に使用しているからといって、ツール自体に欠陥があることを意味するわけではありません。その場合は、「varキーワードが有害と見なされる」や「スレッドが有害と見なされる」などと言えるでしょう。この質問は、標準の品質と性質を、多くのプログラマーが適切に実装および使用するのに苦労していると混同していると思います。


33
-1:単に彼を愛用するのではなく、Artyomのいくつかの異議に対処するのはどうですか?

8
ところで:この記事を書き始めたとき、「UnicodeのSofteareの記事にジョエルは有害だと考えるべきだ」と書きたいと思っていました。多くの間違いがあるからです。たとえば、utf-8エンコーディングは6文字ではなく最大4文字を使用します。また、UCS-2とUTF-16を実際には異なるものとして区別しません。実際に問題を引き起こします。

32
また、Joelがその記事を書いたとき、UTF-8標準は4ではなく6バイトでした。RFC3629は、記事を書いてから数か月後に標準を4バイトに変更しました。インターネット上のほとんどすべてのものと同様に、複数のソースからの読み取り、およびソースの年齢の認識に費用がかかります。リンクは「すべてがすべて終了する」ことを意図したものではなく、出発点でした。

7
utf-8またはutf-32は、ほぼすべての場合の可変長エンコード(BMPを含む)または常に固定長エンコードです。

18
@iconiK:ばかげてはいけません。UTF-16は、テキストを処理するための事実上の標準ではありません。Perlが常に(10年以上も)基礎となるUTF-8表現を持つ抽象文字を内部的に使用していたテキスト処理により適したプログラミング言語を教えてください。このため、すべてのPerlプログラムはすべてのUnicodeを自動的に処理し、ユーザーはばかげたサロゲートを常に気にかける必要はありません。文字列の長さは、コード単位ではなく、コードポイントでのカウントです。それ以外のことは、後方互換性に後方互換性を置く全くの愚かさです。
tchrist

37

Utf-16エンコーディングに問題はありません。ただし、16ビット単位を文字として扱う言語は、設計が不適切であると考えられる可能性があります。char常に文字を表すとは限らない「」という名前の型があると、かなり混乱します。ほとんどの開発者はchar型がコードポイントまたは文字を表すことを期待するため、BMPの近くの文字にさらされると多くのコードが破損する可能性があります。

ただし、utf-32を使用しても、各32ビットコードポイントが常に文字を表すわけではないことに注意してください。文字を組み合わせるため、実際の文字は複数のコードポイントで構成される場合があります。Unicodeは決して簡単ではありません。

ところで。Utf-8が供給される文字が8ビットであると想定するプラットフォームとアプリケーションには、おそらく同じクラスのバグがあります。


12
Javaの場合、タイムライン(java.com/en/javahistory/timeline.jsp)を見ると、Unicodeが16ビットであったときに主にStringの開発が行われたことがわかります(1996年に変更されました)。彼らは、BMP以外のコードポイントを処理する機能を強化する必要があったため、混乱が生じました。
キャシーヴァンストーン

10
@Kathy:しかし、実際にはC#の言い訳ではありません。一般に、CodePoint単一のコードポイント(21ビット)をCodeUnit保持するタイプ、単一のコードユニット(UTF-16の場合は16ビット)を保持するタイプ、およびCharacter完全に書記素をサポートするタイプが必要であることに同意します。しかし、それは機能的に同等になりStringます
Joey

1
この回答はほぼ2年前ですが、コメントするしかありません。「常に文字を表すとは限らない「char」という名前の型を持つことは、かなり混乱します。それでも、人々はCなどで常にそれを使用して、1バイトに格納できる整数データを表します。
JAB

そして、文字エンコーディングを正しく処理しないCコードをたくさん見ました。
-dan04

1
C#には別の言い訳があります。Windows用に設計されており、WindowsはUCS-2上に構築されています(今日のWindows APIでもUTF-8をサポートできないのは非常に迷惑です)。さらに、MicrosoftはJavaの互換性を望んでいたと思います(.NET 1.0にはJava互換性ライブラリがありましたが、Javaサポートはすぐに
なくなりました

20

私の個人的な選択は、常にUTF-8を使用することです。Linuxのほぼすべての標準です。多くのレガシーアプリとの後方互換性があります。非ラテン文字と他のUTF形式に使用される余分なスペースに関しては、オーバーヘッドが非常に小さく、ラテン文字のスペースが大幅に節約されます。ウェブ上では、ラテン語の言語が最高であり、近い将来にそれらが使用されると思います。そして、元の投稿の主な議論の1つに対処するために、ほぼすべてのプログラマーは、UTF-8にマルチバイト文字が含まれることがあることに気付いています。誰もがこれを正しく処理するわけではありませんが、通常、UTF-16で言うことができる以上のことを認識しています。ただし、もちろん、アプリケーションに最適なものを選択する必要があります。そのため、そもそも複数あります。


3
UTF-16はBMP内のあらゆるものに対してよりシンプルであるため、広く使用されています。しかし、私はUTF-8のファンでもあり、バイトオーダーにも問題はありません。
マルコム

2
理論的には、はい。実際には、たとえばUTF-16BEなどがあります。これは、BOMなしのビッグエンディアンでのUTF-16を意味します。これは私が作成したものではなく、ID3v2.4タグで許可されている実際のエンコードです(ID3v2タグは残念ですが、残念ながら広く使用されています)。また、そのような場合、テキスト自体にBOMが含まれていないため、エンディアンを外部で定義する必要があります。UTF-8は常に一方向で記述され、そのような問題はありません。
マルコム

23
いいえ、UTF-16は単純ではありません。難しいです。それは誤解を招き、固定幅だと思い込ませます。手遅れになるまで気付かないので、そのようなコードはすべて壊れています。CASE IN POINT:昨日、Javaコアライブラリでさらに別の愚かなUTF-16バグを発見しました。今回はString.equalsIgnoreCaseで、UCS-2の脳死バグジェリーに残っていたため、16/17の有効なUnicodeコードポイントで失敗します。そのコードはどのくらいの期間使用されていますか?バグがあるという言い訳はありません。UTF-16は、まったく馬鹿げたものになり、事故が起こるのを待っています。UTF-16から叫び声を上げます。
tchrist

3
@tchrist UTF-16が固定長ではないことを知らないためには、非常に無知な開発者でなければなりません。ウィキペディアから始める場合、最上部で以下を読んでください:「コードポイントごとに1つまたは2つの16ビットコード単位の可変長の結果を生成します」。UnicodeのFAQにも同じことが記載されています:unicode.org/faq//utf_bom.html#utf16-1。UTF-16がどこでも可変長であると書かれている場合、どのようにしてだれかを欺くことができるかはわかりません。メソッドについては、UTF-16用に設計されたものではなく、Unicodeを単純なものと見なすべきではありません。
マルコム

2
@tchrist統計のソースはありますか?優れたプログラマーが不足しているとしても、私たちはより価値があるので、これは良いと思います。:) Java APIに関しては、charベースの部分は最終的には非推奨になる可能性がありますが、これはそれらが使用されないという保証ではありません。また、互換性の理由で削除されることはありません。
マルコム

18

まあ、固定サイズのシンボルを使用するエンコーディングがあります。確かにUTF-32を意味します。しかし、各シンボルの4バイトは無駄なスペースが多すぎるため、日常の状況で使用するのはなぜですか?

私の考えでは、ほとんどの問題は、一部のソフトウェアがUnicode標準に遅れをとっていたが、状況を素早く修正できなかったという事実から現れています。Opera、Windows、Python、Qt-それらはすべて、UTF-16が広く知られるようになる前、または存在するようになる前に登場しました。ただし、Opera、Windows Explorer、およびメモ帳では、BMP以外の文字に問題はもうない(少なくとも私のPCでは)ことを確認できます。しかし、とにかく、プログラムがサロゲートペアを認識しない場合、UTF-16は使用されません。そのようなプログラムを扱うことから生じる問題が何であれ、それらはUTF-16自体とは何の関係もありません。

ただし、BMPのみをサポートするレガシーソフトウェアの問題は、いくぶん誇張されていると思います。BMPの外側の文字は、非常に特定のケースおよび領域でのみ発生します。Unicodeの公式FAQによると、「東アジアのテキストであっても、サロゲートペアの発生率は、平均してすべてのテキストストレージの1%未満であるはずです」。もちろん、プログラムはUnicodeに準拠していないため、BMP以外の文字を無視するべきではありませんが、ほとんどのプログラムはそのような文字を含むテキストを操作するためのものではありません。それが彼らがそれをサポートしないなら、それは不快であるが、大惨事ではない理由です。

次に、代替案を考えてみましょう。UTF-16が存在しなかった場合、非ASCIIテキストに適したエンコーディングが得られず、UCS-2用に作成されたすべてのソフトウェアは、Unicode準拠を維持するために完全に再設計する必要があります。後者は、おそらくUnicodeの採用を遅らせるだけです。また、UTF-8がASCIIに関連して行うように、UCS-2のテキストとの互換性を維持することもできませんでした。

さて、すべてのレガシー問題を別にすると、エンコーディング自体に対する議論は何ですか?UTF-16が可変長であることを今日の開発者が知らないことは本当に疑わしい。誰かが問題の可能性として複雑性を指摘した場合、UTF-16はUTF-8よりも解析がはるかに難しくありません。また、UTF-16でのみ文字列の長さを決定するのは簡単に台無しになると考えるのは間違っています。UTF-8またはUTF-32を使用する場合、1つのUnicodeコードポイントが必ずしも1文字を意味するわけではないことに注意する必要があります。それ以外は、エンコーディングに対して実質的な何かがあるとは思わない。

したがって、エンコーディング自体が有害であると考えられるべきではないと思います。UTF-16は単純さとコンパクトさの間の妥協であり、必要な場所で必要なもの使用しても害はありません。場合によってはASCIIとの互換性を維持し、UTF-8が必要です。場合によっては漢字表意文字で作業し、UTF-16を使用してスペースを節約したい場合があります。長さエンコード。より適切なものを使用し、適切に実行してください。


21
それはややまばたきされた、英語中心のビュー、マルコムです。「ASCIIは米国にとって十分であり、他の世界は私たちに適合するはずです」とほぼ同等です。
ジョナサンレフラー

28
実際、私はロシア出身で、自分のプログラムも含めて常にキリル文字に出会っています。そのため、私は英語中心の見解を持っているとは思いません。:) ASCIIに言及することは、Unicodeではなく、特定の文字をサポートしないため、まったく適切ではありません。UTF-8、UTF-16、UTF-32はまったく同じ国際文字セットをサポートし、特定の領域での使用のみを目的としています。そして、これはまさに私のポイントです:あなたが主に英語を使用する場合、UTF-8を使用し、主にキリル文字を使用する場合、UTF-16を使用し、古代言語を使用する場合、UTF-32を使用します。とても簡単です。
マルコム

16
「真実ではありません。日本語、中国語、アラビア語などのアジア言語のスクリプトもBMPに属します。BMP自体は実際には非常に大きく、現在使用されているすべてのスクリプトを含めるのに十分な大きさです」。BMPには0xFFFF文字(65536)が含まれています。中国語だけでもそれ以上のものがあります。中国規格(GB 18030)にはそれ以上のものがあります。Unicode 5.1はすでに100,000文字以上を割り当てています。

12
@Marcolm:「BMP自体は実際には非常に大きく、現在使用されているすべてのスクリプトを含めるのに十分な大きさです」事実ではありません。この時点で、Unicodeはすでに約10万文字を割り当てており、BMPが収容できる以上の方法です。BMPの外側には、中国語の大きな塊があります。そしてそれらのいくつかはGB-18030(必須の中国の標準)によって要求されます。その他は、(必須ではない)日本と韓国の基準で義務付けられています。そのため、これらの市場で何かを販売しようとする場合、BMPを超えるサポートが必要です。

8
UTF-16を使用しているが、狭いBMP文字しか処理できないものは、実際にはUTF-16を使用していません。バギーで壊れています。OPの前提は堅実です。UTF-16は、素朴な人々が壊れたコードを書くことにつながるため、有害です。Unicodeテキストを処理できるか、できないかのどちらかです。できない場合は、ASCIIのみのテキスト処理と同じくらい愚かなサブセットを選択しています。
tchrist

16

特に東アジア言語での長年のWindows国際化作業は私を傷つけたかもしれませんが、文字列の内部からプログラムへの表現にはUTF-16を、プレーンテキストのようなドキュメントのネットワークまたはファイルストレージにはUTF-8を好みます。ただし、通常、WindowsではUTF-16をより高速に処理できるため、WindowsでUTF-16を使用する主な利点があります。

UTF-16への飛躍により、国際的なテキストを処理する平均的な製品の妥当性が劇的に向上しました。サロゲートペアを考慮する必要がある場合(基本的には削除、挿入、改行)がいくつかあり、平均的なケースはほとんど直線的なパススルーです。また、JISバリアントのような以前のエンコーディングとは異なり、UTF-16はサロゲートペアを非常に狭い範囲に制限しているため、チェックは非常に迅速で前後に機能します。

確かに、正しくエンコードされたUTF-8でもほぼ同じくらい高速です。しかし、サロゲートペアを2つのUTF-8シーケンスとして誤ってエンコードする壊れたUTF-8アプリケーションも多数あります。したがって、UTF-8は救いも保証しません。

IEは、通常、UTF-8ページから内部UTF-16表現に変換しているにもかかわらず、2000年以降、サロゲートペアを適切に処理します。Firefoxでも正しく機能していると確信しているので、Operaが何をするかはあまり気にしません。

UTF-32(別名UCS4)はスペースを非常に必要とするため、ほとんどのアプリケーションにとって意味がありません。


6
UTF-8とサロゲートペアに関するコメントはあまり得られませんでした。サロゲートペアは、UTF-16エンコーディングで意味のある概念に過ぎませんか?おそらく、UTF-16エンコーディングからUTF-8エンコーディングに直接変換するコードがこの問題を引き起こす可能性があり、その場合、問題はUTF-8を書き込むのではなく、UTF-16を誤って読み取ることです。そうですか?
クレイグマックイーン

11
Jasonが話しているのは、UTF-8をそのように意図的に実装するソフトウェアです。サロゲートペアを作成し、各半分を個別にUTF-8エンコードします。そのエンコーディングの正しい名前はCESU-8ですが、Oracle(たとえば)はUTF-8としてそれを誤って表します。Javaは、オブジェクトのシリアル化に同様のスキームを採用していますが、「修正UTF-8」として文書化されており、内部での使用のみを目的としています。(今、人々にその文書を読んで、DataInputStream#readUTF()およびDataOutputStream#writeUTF()の不適切な使用をやめることができたら...)

知る限り、UTF-32は可変長エンコードであり、コードポイントの特定の範囲であるUCS4とは異なります。
エオニル

@ Eonil、UTF-32は、UCS5以上のような機能を備えたUnicode標準がある場合に限り、UCS4と区別できます。
ジェイソンTrue

@JasonTrueそれでも、結果が偶然一致するだけで、設計によって保証されているわけではありません。同じことが32ビットメモリアドレス指定、Y2K、UTF16 / UCS2でも発生しました。または、その平等の保証はありますか?もしあれば、喜んで使用します。しかし、壊れやすいコードを書きたくありません。私は文字レベルのコードを書いていますが、UTF <->コードポイント間でトランスコードするための保証された方法がないことは、多くの人を悩ませています。
エオニル

16

UTF-8は間違いなく進むべき道であり、おそらく、高性能のランダムアクセスを必要とする(ただし、文字の組み合わせを無視する)アルゴリズムで内部的に使用するUTF-32を伴います。

UTF-16とUTF-32(およびそのLE / BEバリアント)の両方がエンディアンの問題に悩まされているため、外部で使用しないでください。


9
UTF-8では一定時間のランダムアクセスも可能です。コードポイントではなくコード単位を使用してください。本当のランダムなコードポイントアクセスが必要なのかもしれませんが、ユースケースを見たことがないので、代わりにランダムな書記素クラスタアクセスが必要になります。

15

UTF-16?間違いなく有害です。ここに私の目玉はありますが、プログラム内のテキストには3つの許容されるエンコードがあります。

  • ASCII:より良いものを買う余裕のない低レベルのもの(例:マイクロコントローラー)を扱う場合
  • UTF8:ファイルなどの固定幅メディアでのストレージ
  • 整数コードポイント(「CP」?):プログラミング言語およびプラットフォームに便利な最大整数の配列(低リソースの制限でASCIIに減衰)。古いコンピューターではint32であり、64ビットアドレス指定の場合はint64である必要があります。

  • 明らかに、レガシーコードへのインターフェースは、古いコードを正しく機能させるために必要なエンコーディングを使用します。


4
@simon buchan、U+10ffff最大値は、コードポイントを使い果たした場合(そうでない場合)にウィンドウから消えます。ただし、p50システムでint32を使用して速度を上げるのはおそらく安全です。なぜならU+ffffffff、2050年頃に128ビットシステム用にコードを書き直すことを強制される前に超えてしまうとは思えないからです。 「利用可能な最大のサイズ」(おそらくint256またはbignumsなど)とは対照的に、「便利です」
デイビッドX

1
@David:Unicode 5.2は107,361コードポイントをエンコードします。867,169個の未使用のコードポイントがあります。「いつ」はばかげています。Unicodeコードポイントは、UTF-16が依存するプロパティである0〜0x10FFFFの数値として定義されます。(64ビットシステムがインターネット全体をアドレス空間に保持できる場合、2050も128ビットシステムの推定値を低く抑えているようです。)

3
@David:あなたの「いつ」は、128ビットスイッチではなくUnicodeコードポイントの不足を指していました。メモリとは異なり、文字の指数関数的な増加はないため、Unicodeコンソーシアムは上記のコードポイントを決して割り当てないことを明確に保証しています。これは、21ビット十分な場合の状況の1つです。U+10FFFF

10
@Simon Buchan:少なくとも最初の連絡まで。:)

3
Unicodeは、U + FFFFを超えるコードポイントがないことを保証するために使用されていました。
シャノン退職

13

Unicodeはコードポイントを最大0x10FFFF(1,114,112コード)まで定義します。文字列/ファイル名などを扱う多言語環境で実行されるすべてのアプリケーションは、それを正しく処理する必要があります。

UTF-16:1,112,064コードのみをカバーします。ユニコードの終わりにあるものは、プレーン15-16(プライベート使用領域)からのものです。Utf-16の概念を破る以外は、これ以上成長することはできません。

UTF-8:理論的には2,216,757,376コードをカバーしています。現在のUnicodeコードの範囲は、最大4バイトのシーケンスで表すことができます。バイトオーダーの問題はなく、asciiと「互換性」があります。

UTF-32:理論的には2 ^ 32 = 4,294,967,296コードをカバーします。現在、可変長のエンコードは行われておらず、おそらく今後も使用されないでしょう。

これらの事実は自明です。Utf-16の一般的な使用を推奨することを理解していません。可変長エンコード(インデックスでアクセスできない)で、現在でもUnicodeの範囲全体をカバーするのに問題があり、バイトオーダーを処理する必要があるなど。Windowsおよび他の場所。マルチプラットフォームコードを記述する場合でも、Utf-8をネイティブで使用し、プラットフォームに依存する方法でエンドポイントでのみ変換を行うことをお勧めします(既に提案したとおり)。インデックスによる直接アクセスが必要で、メモリに問題がない場合は、Utf-32を使用する必要があります。

主な問題は、Windows Unicode = Utf-16を扱う多くのプログラマーが、可変長エンコードされているという事実さえ知らない、または無視しないことです。

通常は* nixプラットフォームでの方法はかなり良く、c文字列(char *)はUtf-8エンコードとして解釈され、ワイドc文字列(wchar_t *)はUtf-32として解釈されます。


7
注:Unicodeコンソーシアムは、10FFFFがUnicodeの上位範囲であり、UTF-8の最大4バイト長を定義し、有効なコードポイント範囲から0xD800-0xDFFFの範囲を明示的に除外し、この範囲はサロゲートペア。したがって、有効なUnicodeテキストは、これらのエンコードのそれぞれで表すことができます。また、将来への成長について。将来的には100万コードポイントでは十分ではないようです。

7
@Kerrek:誤り:UCS-2は有効なUnicodeエンコーディングではありません。定義によるすべてのUTF- *エンコーディングは、交換に合法なUnicodeコードポイントを表すことができます。UCS-2は、それよりもはるかに少ない数に加えて、さらにいくつかを表すことができます。繰り返し:UCS-2は、ASCIIよりも有効なUnicodeエンコーディングではありません。
tchrist

1
「私は一般的な使用提唱理解していないUTF-8をそれが符号化された可変長である(インデックスによってアクセスできません)。」
イアン・ボイド

9
@Ian Boyd、ランダムアクセスパターンで文字列の個々の文字にアクセスする必要性は、信じられないほど誇張されています。文字の行列の対角線を計算するのと同じくらい一般的ですが、これは非常にまれです。文字列は事実上常に連続して処理され、 UTF-8 char Nにいる場合にUTF-8 char N + 1にアクセスするのはO(1)なので、問題はありません。文字列のランダムアクセスを行う必要はほとんどありません。UTF-8ではなくUTF-32に移行する価値があると思うかどうかはあなた自身の意見ですが、私にとってはまったく問題ではありません。
tchrist

2
@tchrist、逆シーケンシャルを「シーケンシャル」として含め、文字列の後端と既知の文字列をもう少し比較することで、文字列が事実上常に連続して処理されることを認めます。2つの非常に一般的なシナリオは、文字列の末尾から空白を切り捨てることと、パスの末尾のファイル拡張子を確認することです。
アンディデント

11

これをリストに追加します。

提示されたシナリオは単純です(ここで説明するのは元よりもさらに単純です!):1. WinForms TextBoxは空のフォーム上にあります。MaxLengthが20に設定されています。

2.ユーザーはTextBoxに入力するか、テキストを貼り付けます。

3. TextBoxに入力または貼り付けても、20に制限されますが、20を超えるテキストで共感的にビープ音が鳴ります(ここではYMMV。サウンドスキームを変更してその効果を実現しました!)。

4.エキサイティングな冒険を始めるために、小さなテキストのパケットが別の場所に送信されます。

これは簡単なシナリオであり、空き時間に誰でも作成できます。退屈して以前は試したことがないので、WinFormsを使用して複数のプログラミング言語で自分で書きました。そして、複数の実際の言語のテキストを使用しているのは、私がそのように配線されており、恐ろしい宇宙全体の誰よりも多くのキーボードレイアウトを持っているからです。

私は退屈を改善するために、Magic Carpet Rideという名前を付けました。

これは価値がありましたが、うまくいきませんでした。

代わりに、次の20 文字をMagic Carpet Rideフォームに入力しました。

0123401234012340123𠀀

ええとああ。

その最後のキャラクターは、Unicodeの最初の拡張B表意文字であるU + 20000です(別名U + d840 U + dc00、親しい友人であり、彼が前に姿を消したことを恥じていない)。

ここに画像の説明を入力してください

そして今、私たちは球技をしています。

TextBox.MaxLengthが話すとき

テキストボックスに手動で入力できる最大文字数を取得または設定します。

それが本当に意味することは

テキストボックスに手動で入力できるUTF-16 LEコードユニットの最大数を取得または設定し、誰かに夢中になっているだけの言語的文字概念でキュートなゲームをプレイしようとする文字列から生きているがらくたを容赦なく切り捨てますカプランの仲間は攻撃的だと思うだろう(彼はもっと外に出なければならない!)。

私は、ドキュメントの更新....得ることについて試してみて参照してくださいよ
、私の覚えている正規の読者UTF-16にUCS-2のシリーズは、単純化の概念と私の不幸に注意しますTextBox.MaxLengthを、どのようにそれは最低でもこのケースを処理する必要がありますその厳格な動作が違法なシーケンスを作成する場合、.Net Frameworkの他の部分は

  • System.Text.EncoderFallbackException:インデックス0のUnicode文字\ uD850を指定されたコードページに変換できません。*

この文字列を.Net Frameworkの別の場所に渡す場合は例外です(同僚のダントンプソンが行っていたように)。

大丈夫、おそらくUCS-2からUTF-16への完全なシリーズは、多くの人の手の届かないところにあります。
しかし、TextBox.TextがSystem.Stringを生成しないと予想するのは合理的ではありません それにより、.Net Frameworkの別の部分がスローされなくなりますか?つまり、コントロール上で何らかのイベントという形で、スマートな検証を簡単に追加できる、今後の切り捨てを通知するような機会はありません。つまり、コントロール自体が実行しても構わないという検証です。このパンクコントロールは、予期せぬ例外を引き起こしてアプリケーションを粗野なサービス拒否として終了させる可能性がある場合、セキュリティ上の問題につながる可能性がある安全契約を破っていると言っても過言ではありません。WinFormsのプロセス、メソッド、アルゴリズム、または手法が無効な結果を生成するのはなぜですか?

ソース:Michael S. Kaplan MSDNブログ


ありがとう、とても良いリンク!質問の問題リストに追加しました。

9

UTF-16が有害であるとは必ずしも言えません。エレガントではありませんが、GB18030がGB2312で、UTF-8がASCIIで行うように、UCS-2との後方互換性の目的を果たします。

しかし、MicrosoftとSunが16ビット文字の周りに巨大なAPIを構築した後、ミッドストリームでUnicodeの構造に根本的な変更を加えることは有害でした。変化に対する認識を広められなかったことは、より有害でした。


8
UTF-8はASCIIのスーパーセットですが、UTF-16はUCS-2のスーパーセットではありません。ほとんどスーパーセットですが、UCS-2をUTF-8に正しくエンコードすると、CESU-8として知られる憎悪が生じます。UCS-2にはサロゲートはなく、通常のコードポイントだけがあるため、そのように変換する必要があります。UTF-16の本当の利点は、UTF-8を完全に書き換えるよりもUCS-2コードベースをアップグレードする方が簡単なことです。おかしいね?

1
確かに、技術的にはUTF-16はUCS-2のスーパーセットではありませんが、U + D800からU + DFFFがUTF-16サロゲート以外に使用されたのはいつですか?
dan04

2
関係ありません。バイトストリームを盲目的に通過する以外の処理では、サロゲートペアをデコードする必要があります。サロゲートペアをUCS-2として扱う場合は、サロゲートペアをデコードできません。

6

UTF-16は、処理とスペースの最適な妥協点です。そのため、ほとんどの主要プラットフォーム(Win32、Java、.NET)は、文字列の内部表現にUTF-16を使用しています。


31
-1。UTF-8の方が小さいか、それほど大きくない可能性が高いためです。特定のアジア言語のスクリプトでは、UTF-8はグリフあたり3バイトですが、UTF-16は2バイトだけですが、これはUTF-8がASCIIの1バイトだけであるためバランスが取れていますもの)。さらに、上記の言語では、グリフはラテン文字よりも多くの情報を伝達するため、グリフはより多くのスペースを取ることが正当化されます。

32
私は両方のオプションの最悪の側面を組み合わせることは良い妥協とは言いません。

18
UTF-8よりも簡単ではありません。それも可変長です。
ルイスキューバル

36
UTF-16の利点についての議論はさておき、引用したのは、UTF-16を使用するWindows、Java、または.NETの理由ではありません。WindowsとJavaは、Unicodeが16ビットエンコーディングであった時代にさかのぼります。UCS-2は当時合理的な選択でした。Unicodeが21ビットエンコーディングになったとき、UTF-16に移行することが、既存のプラットフォームが持つ最良の選択でした。これは、取り扱いの容易さやスペースの妥協とは関係ありませんでした。それは単なるレガシーの問題です。
ジョーイ

10
ここで.NETはWindowsのレガシーを継承します。
ジョーイ

6

UTF-16のポイントを理解したことはありません。最もスペース効率の良い表現が必要な場合は、UTF-8を使用してください。テキストを固定長として処理できるようにする場合は、UTF-32を使用します。どちらも必要ない場合は、UTF-16を使用します。さらに悪いことに、UTF-16の一般的な(基本的な多言語プレーン)文字はすべて単一のコードポイントに収まるため、UTF-16が固定長であると想定しているバグは微妙で見つけにくいですが、 UTF-8を使用すると、国際化を試みるとすぐにコードが高速かつ大音量で失敗します。


6

私はまだコメントできないので、これを回答として投稿しutf8everywhere.orgます。他のスタックエクスチェンジで十分な評判を得ているので、コメント権限を自動的に取得できないのは残念です。

これは意見へのコメントとして意図されています。はい、UTF-16は有害な回答と見なされるべきです。

ちょっとした修正:

誤ってUTF-8 char*をWindows-API関数のANSI文字列バージョンに渡さUNICODEないようにするには、ではなくを定義する必要があります_UNICODE。にではなくに_UNICODE関数をマップします。代わりに、後者が定義します。証拠として、これはMS Visual Studio 2005のヘッダーからのものです。_tcslenwcslenMessageBoxMessageBoxWUNICODEWinUser.h

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

最低限、このエラーはで修正する必要がありますutf8everywhere.org

提案:

おそらく、このガイドには、データ構造のワイド文字列バージョンの明示的な使用例が含まれている必要があります。これにより、見逃したり忘れたりしにくくなります。関数のワイド文字列バージョンの使用に加えてデータ構造の文字列ワイドバージョンを使用すると、そのような関数のANSI文字列バージョンを誤って呼び出す可能性がさらに低くなります。

例の例:

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
if (hSearch != INVALID_HANDLE_VALUE)
{
    FindClose(hSearch);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
}

同意した; ありがとう!ドキュメントを更新します。このドキュメントには、さらに多くの開発とデータベースに関する情報の追加が必要です。私たちは文言の貢献を喜んで受け取ります。
パベルラジビロフスキー

@PavelRadzivilovskyは_UNICODE:(まだそこにある
cubuspl42

思い出してくれてありがとう。キューバ、ジェレ、SVNのユーザーになりませんか?
パベルラジビロフスキー14

@Pavel確かに、感謝します!
ジェルゲルツ14

@JelleGeerts:この遅延についておaび申し上げます。メール(マニフェストからリンク)またはFacebookでいつでもご連絡いただけます。見つけるのは簡単です。ここであなたがもたらした問題を修正したと思います(そして、私はそこにあなたの功績があると信じています)が、UTF-8とUTF-16の議論全体は依然として関連しています。あなたが貢献するより多くがある場合は、それらのプライベートチャンネルを通じてお気軽にお問い合わせください。
イブンガロビル

5

誰かがUCS4とUTF-32は同じだと言った。いいえ、しかし、私はあなたが何を意味するか知っています。ただし、一方は他方のエンコードです。ここでエンディアンネスの戦いが起こらないように、最初からエンディアンネスを指定したいと思っていたらと思います。彼らはそれが来るのを見ていなかっただろうか?少なくともUTF-8はどこでも同じです(誰かが6バイトで元の仕様に従っていない限り)。

UTF-16を使用する場合は、マルチバイト文字の処理を含める必要があります。2Nをバイト配列にインデックス付けしてN番目の文字に移動することはできません。あなたはそれを歩くか、文字インデックスを持っている必要があります。それ以外の場合は、バグを作成しました。

C ++の現在のドラフト仕様では、UTF-32およびUTF-16はリトルエンディアン、ビッグエンディアン、および不特定のバリアントを持つことができると述べています。本当に?誰もが最初からリトルエンディアンを実行する必要があるとUnicodeが指定していた場合、それはすべて単純でした。(ビッグエンディアンでも大丈夫だったでしょう。)その代わりに、一部の人々はそれをある方法で実装し、別の方法で実装しました。ソフトウェアエンジニアになるのは恥ずかしいことです。


不特定のエンディアネスには、文字列を読み取る方法を決定するために使用される最初の文字としてBOMが含まれることになっています。UCS-4とUTF-32は確かに最近では同じです。つまり、32ビット整数に格納された0〜0x10FFFFの数値UCS値です。

5
@Tronic:技術的には、これは真実ではありません。UCS-4は任意の32ビット整数を格納できますが、UTF-32は、0xFFFF、0xFFFE、およびすべてのサロゲートなど、交換に違法な非文字コードポイントの格納を禁止されています。UTFはトランスポートエンコーディングであり、内部エンコーディングではありません。
tchrist

異なるプロセッサが異なるバイト順序を使用し続ける限り、エンディアンの問題は避けられません。ただし、UTF-16のファイルストレージに「優先」バイト順があればいいかもしれません。
Qwertie

UTF-32はコードポイントの固定幅ですが、文字の固定幅ではありません。(「文字の結合」と呼ばれるものを聞いたことがありますか?)したがって、4Nをバイト配列にインデックス付けするだけでは、N番目の文字に移動できません。
ムシフィル14年

2

開発者が十分に注意を払っていれば有害だとは思いません。
そして、彼らもよく知っているなら、彼らはこのトレードオフを受け入れるべきです。

日本のソフトウェア開発者として、UCS-2は十分に大きく、スペースを制限するとロジックが明らかに簡素化され、ランタイムメモリが削減されるため、UCS-2の制限下でutf-16を使用するだけで十分です。

コードポイントとバイトが比例していることを前提とするファイルシステムまたは他のアプリケーションがあります。そのため、生のコードポイント番号が固定サイズのストレージに適合することが保証されます。

1つの例は、ファイル名ストレージエンコーディングとしてUCS-2指定するNTFSおよびVFATです。

それらの例が本当にUCS-4をサポートするために拡張したい場合、とにかくすべてにutf-8を使用することに同意できますが、固定長には次のような良い点があります:

  1. 長さによってサイズを保証できます(データサイズとコードポイントの長さは比例します)
  2. ハッシュルックアップにエンコード番号を使用できます
  3. 非圧縮データは適切なサイズです(utf-32 / UCS-4と比較)

埋め込みデバイスでもメモリ/処理能力が安い将来、余分なキャッシュミスやページフォールト、余分なメモリ使用のためにデバイスが少し遅いことを受け入れるかもしれませんが、これは近い将来起こりません...


3
このコメントを読んでいる人にとって、UCS-2はUTF-16と同じものではないことに注意する価値があります。違いを調べて理解してください。
mikebabcock

1

「最も人気のあるエンコーディングの1つであるUTF-16は有害と見なされますか?」

かなり可能性がありますが、代替案が必ずしもはるかに優れていると見なされるべきではありません。

基本的な問題は、グリフ、文字、コードポイント、バイトシーケンスに関する多くの異なる概念があることです。これらのそれぞれの間のマッピングは、正規化ライブラリを使用しても簡単ではありません。(たとえば、ラテン語ベースのスクリプトで書かれたヨーロッパ言語の一部の文字は、単一のUnicodeコードポイントで書かれていません。そして、それは複雑さのより単純な終わりにあります!)難しい; 奇妙なバグが予想されます(ここでそれらについてうめくのではなく、関連するソフトウェアのメンテナー伝えてください)。

UTF-8とは対照的に、UTF-16が有害と見なされる唯一の方法は、BMPの外側のコードポイントを(サロゲートのペアとして)異なる方法でエンコードすることです。コードがコードポイントにアクセスしたり、コードポイントごとに反復したい場合は、その違いに注意する必要があります。OTOH、「文字」を前提とする既存のコードの大部分は常に2バイトの量に収まることを意味します。かなり一般的で、間違っていれば、少なくともすべてを再構築せずに動作し続けることができます。言い換えれば、少なくとも、正しく処理されていないキャラクターを見ることができます!

私はあなたの質問に頭を向けて、ユニコードのいまいましいシバン全体が有害であると考えられるべきであり、誰もが8ビットエンコーディングを使用するべきだと言います。さまざまなISO 8859エンコーディング、さらにキリル文字に使用される一連のエンコーディング、およびEBCDICスイートに対する混乱、そして…そのすべての欠点に対するUnicodeはそれを打ち負かしています。異なる国の誤解の間のそれほど厄介な妥協ではなかった場合に限ります。


運がわかれば、数年後にはUTF-16のスペースが不足することになります。えー
ドナルドフェローズ

3
基本的な問題は、テキストが一見難しいです。その情報をデジタルで表現するためのアプローチは複雑ではありません。日付が難しい、カレンダーが難しい、時間が難しい、個人の名前が難しい、住所が難しいのと同じ理由です。デジタルマシンが人間の文化的構造と交差するたびに、複雑さが爆発します。それは人生の事実です。人間はデジタルロジックでは機能しません。
アリストテレスPagaltzis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.