2016-12-03 5 views
2

У меня есть этот код для преобразования букв в прописные:Преобразование символов в верхний регистр на арабском

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

Он работал в течение многих лет. Недавно меня попросили поддержать арабский, и мой пользователь сказал, что письма развращаются. Это из-за вышеуказанного кода.

Я сказал по-арабски, что прописные буквы не применяются. Я знаю, что могу проверить свои настройки программы, чтобы убедиться, что они используют арабский язык и избегают этого кода. Но есть ли другой путь?

Я знаю с датами, которые вы вызываете, например, _tsetlocale.

Обновление:

Расположенный на тему о toupper которой упоминается языковой стандарт! Попробуй.

ответ

2

Как вы обнаружили, классические процедуры преобразования, такие как 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, который указывает на то, что это функции преобразования, поддерживающие язык. Они позволяют вам передать явный язык, который будет использоваться при преобразовании.

+0

Фантастический ответ. Сегодня я расскажу об этом позже. –

0

Я предполагаю, что вы используете строки UTF-8. В этом случае ваш код должен быть совместимым с UTF-8, то есть иметь возможность учитывать многобайтовые символы. Например, если второй символ в двухбайтовой строке имеет то же значение, что и буква «c», он будет подхвачен вашим кодом и преобразован в верхний регистр, что приведет к совершенно другому двухбайтовому символу. Взгляните на этот вопрос: Convert a unicode String In C++ To Upper Case

Смежные вопросы