LINUX.ORG.RU

Приведение к верхнему регистру

 , ,


0

1

Имеется программа на 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», по «ц» — «Технологии пришельцев», по «й» — «Технологии людей».

★★★★★

Последнее исправление: question4 (всего исправлений: 5)
Ответ на: комментарий от xaizek

Автор объяснил. Поиск заодно проверяет стринги, которые закопаны в глубинах интерфейса. Букву «й» находило в наборе «Все технологии людей» + «Огнестр. оружие» + «Пистолеты» + «Маскируемое снаряжение» + «Glock 18».

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Тогда понятно. Это надо куда-нибудь в комментарий в коде добавить.

xaizek ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.