Преобразовать регистр широких символов, учитывая LCID (Visual C++)
У меня есть некоторый существующий код Visual C++, где мне нужно добавить преобразование строк широких символов в верхний или нижний регистр.
Я знаю, что в этом есть подводные камни (например, турецкое "Я"), но большинство из них можно устранить, если вы знаете язык. К счастью, в этой области кода я знаю значение LCID (ID локали), которое, как я полагаю, совпадает со знанием языка.
Поскольку LCID относится к типу Windows, существует ли функция Windows, которая преобразует широкие строки в верхний или нижний регистр?
Runtime-функция C _towupper_l() звучит так, как будто она идеальна, но вместо LCID принимает параметр _locale_t, поэтому я думаю, что она не подходит, если нет абсолютно надежного способа преобразования LCID в _locale_t.
1 ответ
Функция, которую вы ищете, называется LCMapString
и это часть API-интерфейсов Windows NLS. LCMAP_UPPERCASE
флаг отображает символы в верхний регистр, а LCMAP_LOWERCASE
отображает символы в нижний регистр
Для приложений, ориентированных на Windows Vista и более поздние версии, существует Ex
вариант, который работает с именами локалей, а не идентификаторами, которые, по словам Microsoft, вы должны использовать.
Фактически, в реализации CRT, предоставляемой с VS 2010 (и, возможно, и с другими версиями), такие функции, как _towupper_l
в конечном итоге звонит LCMapString
после того, как они извлекают идентификатор локали (LCID) из указанного _locale_t
,
Если вы похожи на меня и менее знакомы с API i8n, чем должны быть, вы, вероятно, уже знаете о CharUpper
, CharLower
, CharUpperBuff
, а также CharLowerBuff
семейство функций. Это были старые резервы с ранних дней Windows для изменения регистра символов / строк, но, как предупреждает их документация:
Обратите внимание, что
CharXxx
всегда отображает верхний регистр I в нижний регистр I ("i"), даже если текущий язык турецкий или азербайджанский. Если вам нужна функция, чувствительная в этом отношении к лингвистическомуLCMapString
,
То, что он игнорирует, упоминается в нескольких постах в замечательном блоге Майкла Каплана по вопросам интернационализации: что означает "лингвистический корпус"? Как лучше всего переделать дело. Резюме заключается в том, что вы достигаете тех же результатов, что и CharXxx
семейство функций путем вызова LCMapString
и не указав LCMAP_LINGUISTIC_CASING
флаг, в то время как вы можете быть лингвистически чувствительными, гарантируя, что вы действительно указываете LCMAP_LINGUISTIC_CASING
флаг.
Образец кода:
std::wstring test("Does my code pass the Turkey test?");
if (!LCMapStringW(lcid, /* your LCID, defined elsewhere */
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,
test.c_str(), /* input string */
test.length(), /* length of input string */
&test[0], /* output buffer (can reuse input) */
test.length())) /* length of output buffer (same as input) */
{
// Uh-oh! Something went wrong in the call to LCMapString, so you need to
// handle the error somehow here.
// A good start is calling GetLastError to determine the error code.
}