2

文字を大文字に変換する次のコードがあります。

// make this character upper
if(_istalpha(zChar) && !_istupper(zChar))
   pMsg->wParam = (WPARAM)_toupper(zChar);

それは何年も働いています。最近、アラビア語をサポートするように依頼されましたが、ユーザーは文字が壊れていると言っていました。上記のコードが原因です。

大文字は当てはまらないとアラビア語で言われました。プログラムの設定をテストして、アラビア語を使用しているかどうかを確認し、このコードを回避できることを知っています。しかし、別の方法はありますか?

_tsetlocaleたとえば、最初に電話する日付を知っています。

アップデート:

ロケール設定に言及しているtoupperに関するこのトピックを見つけました! 試してみます。

4

2 に答える 2

2

toupperお気づきのように、CRTや Win32 のような古典的な変換ルーチンCharUpperはかなり馬鹿げています。それらは一般に、すべての世界が ASCII であると想定されていた時代に由来します。

必要なのは、言語に敏感な変換です。これは計算コストの高い操作ですが、正しく実装するのも非常に困難です。言語は難しいです。そのため、可能であれば責任を標準ライブラリにオフロードしたいと考えています。MFC を使用しているので、明らかに Windows オペレーティング システムをターゲットにしていることになります。つまり、あなたは幸運です。Microsoft のローカリゼーション エンジニアの懸命な作業に便乗することで、シェルや他の OS コンポーネントとの一貫性という追加の利点を得ることができます。

呼び出す必要がある関数はLCMapStringEx(またはLCMapString、まだ Vista より前のプラットフォームをターゲットにしている場合) です。この関数の署名の複雑さは、適切な言語認識文字列処理の複雑なタスクに対する強力な証拠として機能します。

  • まず、ロケールを選択する必要があります。通常は、 で指定できるユーザーのデフォルト ロケールが必要ですLOCALE_NAME_USER_DEFAULTが、ここでは何でも使用できます。
  • フラグについては、LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING. 逆の操作を行うには、 を使用しますLCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING。ここには、覚えておくべき興味深い便利なオプションが他にもたくさんあります。
  • 次に、ソース文字列へのポインターと、その長さ (コード単位) を取得します。
  • また、結果を受け取る文字列バッファーへのポインターと、その最大文字数 (コード単位) です。
  • 最後の 3 つのパラメーターは、単純に NULL または 0 に設定できます。

すべてを一緒に入れて:

BOOL ConvertToUppercase(std::wstring& buffer)
{
    return LCMapStringEx(LOCALE_NAME_USER_DEFAULT  /* or whatever locale you want */,
                         LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,
                         buffer.c_str(),
                         buffer.length(),
                         &buffer[0],
                         buffer.length(),
                         NULL,
                         NULL,
                         0);
}

ここではバッファの内容のインプレース変換を行っていることに注意してください。したがって、大文字の文字列は元の入力文字列とまったく同じ長さであると想定しています。これはおそらく正しいですが、普遍的に安全な仮定ではない可能性があるため、そのようなエラーの処理を追加するか ( ERROR_INSUFFICIENT_BUFFER)、防御的にバッファーに余分なパディングを追加する必要があります。

現在行っているように CRT 関数を使用したい場合_totupper_l、そのフレンドはLCMapString/のラッパーLCMapStringExです。_lこれらがロケール対応の変換関数であることを示す接尾辞に注意してください。変換で使用される明示的なロケールを渡すことができます。

于 2016-12-03T08:41:58.310 に答える
0

UTF-8 文字列を使用していると仮定します。この場合、コードは UTF-8 に対応している必要があります。つまり、マルチバイト文字を考慮できる必要があります。たとえば、2 バイト文字列の 2 番目の文字がたまたま文字 'c' と同じ値である場合、それはコードによって取得され、大文字に変換され、まったく異なる 2 バイト文字になります。この質問を見てください: Convert a unicode String In C++ To Upper Case

于 2016-12-05T18:16:00.303 に答える