Имеется программа на C++, где в ряде мест проводится сравнение вводимого пользователем текста с имеющимся набором строк. При этом сравниваемые строки приводятся к верхнему регистру вызовом std::towupper. Для 26 английских символов это работает, для остальных — нет.
Как я понял, проблема в том, что в соответствующих местах программы текущей локалью является «C». Если перед вызовом towupper переключиться на локаль с UTF-8, например вызвать
std::setlocale(LC_ALL, "ru_RU.utf8");
В программе уже имеются 8 вызовов setlocale: перед каждым вызовом функций, преобразующих wide string в multibyte и multibyte в wide вызывается
setlocale(LC_ALL, "");
setlocale(LC_ALL, "C");
Вопросы:
1. Подозреваю, что локаль «ru_RU.utf8» для большинства пользователей недоступна. Какая локаль с UTF-8 гарантированно есть у всех? «en_US.utf8»? Или вызвать для "", считая, что сейчас у всех неангличан системная локаль юникодная? Или это сработает для соответствующего языка и в неюникодной локали? — Единогласно решили вызывать "", а у кого ещё нет Юникода — их проблема.
2. Когда и где вызывать setlocale? Перед каждым блоком вызовов towupper? — Да. А потом сбрасывать в «C».
3. Как сохранить текущее состояние локали, чтобы к нему потом вернуться? Или не заморачиваться и считать что всюду «C»? — Да, всюду «C».
4. Какая категория отвечает за правила смены регистра? LC_COLLATE? LC_CTYPE? Или тоже не заморачиваться и писать всюду LC_ALL? — Проще конвертировать функцией toupper, у которой 2-й параметр — имя локали. Если в итераторе требуется функция с 1 параметром, писать лямбду либо приватную функцию, которая внутри вызывает toupper с нужным параметром.
Итог: https://github.com/MeridianOXC/OpenXcom/commit/31594f7c7e45bf0c1e0868975ef6da...
Поиск работает, но функция, которая использует std::transform(...), иногда находит одиночные русские буквы в строках, где их нет. Так, буква «ц» нашлась в:
«Heavy plasma»
«Heavy plasma clip»
«Малая пусковая установка»
«Парализующая бомба»
«й» нашлась в:
«Glock 18»
«Магазин Glock 18»
«w» нашлась в:
«Bone Club»
«Shogg Staff»
«Tonfa»
«Baseball Bat»
и ещё более 100 совпадений.
Для более длинных поисковых запросов ложноположительные ответы не обнаружены.
Так как проблема с «w» проявляется и в непатченой программе, можно считать патч рабочим.
Дополнение: Как объяснил вернувшийся автор, поиск ведётся по набору стрингов, которые видны не на всех экранах или через подменю — не только название предмета, но и категории: «подводное оружие», «холодное оружие», «боеприпасы» и т.п.. В частности, по «w» находит предметы категории «Underwater», по «ц» — «Технологии пришельцев», по «й» — «Технологии людей».