Как вы обнаружили, классические процедуры преобразования, такие как CRT toupper
и Win32's CharUpper
, довольно тупые. Обычно они родом с того времени, когда весь мир считается ASCII.
Что вам нужно - это лингвистически-чувствительное преобразование. Это вычислительно более дорогостоящая операция, но и очень сложно реализовать правильно. Языки трудны. Поэтому вы хотите разгрузить ответственность, если это вообще возможно для стандартной библиотеки. Поскольку вы используете MFC, вы, очевидно, нацелены на операционную систему Windows, а это значит, что вам повезло. Вы можете справиться с тяжелой работой инженеров по локализации Microsoft, давая дополнительное преимущество согласованности с оболочкой и другими компонентами ОС.
Функция, которую необходимо вызвать, - LCMapStringEx
(или LCMapString
, если вы все еще нацелены на платформы до Vista). Сложность подписи этой функции служит убедительным доказательством сложной задачи правильной лингвистически-ориентированной обработки строк.
- Во-первых, вам нужно выбрать локаль. Вы обычно хотите установить локаль пользователя по умолчанию, которую вы можете указать с помощью
LOCALE_NAME_USER_DEFAULT
, но вы можете использовать все, что хотите здесь.
- Для флагов вам понадобится
LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING
. Чтобы выполнить обратную операцию, вы должны использовать LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING
. Здесь также есть много других интересных и полезных вариантов.
- Тогда у вас есть указатель на исходную строку и ее длину в символах (единиц кода).
- И указатель на строковый буфер, который получает результаты, а также его максимальную длину в символах (единицах кода).
- Последние три параметр может быть просто установлен в 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);
}
Обрати внимание, что я делаю конверсию в месте здесь содержаний буфера и, следовательно, предполагая, что строка с верхним регистром точно такая же длина, что и исходная строка ввода. Это возможно true, но может и не быть универсально безопасным допущением, поэтому вы либо захотите добавить обработку для таких ошибок (ERROR_INSUFFICIENT_BUFFER
), и/или защитно добавить дополнительное дополнение в буфер.
Если вы предпочитаете использовать функции CRT, как сейчас, _totupper_l
и его друзья - обертки вокруг LCMapString
/LCMapStringEx
. Обратите внимание на суффикс _l
, который указывает на то, что это функции преобразования, поддерживающие язык. Они позволяют вам передать явный язык, который будет использоваться при преобразовании.
Фантастический ответ. Сегодня я расскажу об этом позже. –