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
これらがロケール対応の変換関数であることを示す接尾辞に注意してください。変換で使用される明示的なロケールを渡すことができます。