Преобразование широкой строки char в нижний регистр в С++

Как преобразовать строку wchar_t из верхнего регистра в нижний регистр в С++?

Строка содержит смесь японских, китайских, немецких и греческих символов.

Я думал об использовании towlower ...

http://msdn.microsoft.com/en-us/library/8h19t214%28VS.80%29.aspx

.. но в документации сказано, что:

Преобразование регистра towlower зависит от локали. При этом изменяются только символы, относящиеся к текущей локали.

Редактировать: Может быть, мне следует описать, что я делаю. Я получаю поисковый запрос Unicode от пользователя. Первоначально он был в кодировке UTF-8, но я конвертирую его в широкоформатный (могу ошибаться в формулировке). Мой отладчик (VS2008) правильно отображает японские, немецкие и т. д. символы в «переменных быстрых просмотрах». Мне нужно просмотреть еще один набор данных в Unicode и найти совпадения строки поиска. Хотя это не проблема для меня, когда поиск чувствителен к регистру, более проблематично сделать это без учета регистра. Мой (возможно, наивный) подход к решению проблемы состоял бы в том, чтобы преобразовать все входные и выходные данные в нижний регистр, а затем сравнить их.


person Nitramk    schedule 23.10.2009    source источник
comment
другим подходом было бы использование алгоритмов сравнения, которые игнорируют регистр. И случай не единственная ваша проблема. Например, без нормализации строки диакритические знаки можно считать частью одного (é, Õ) или нескольких отдельных символов ('e, ~O). Правильная нормализация (NFC/NFD/NFKC/NFKD) перед сравнением жизненно важна в вашей ситуации.   -  person Abel    schedule 23.10.2009
comment
Авель, пожалуйста, опубликуйте это как правильный ответ, чтобы за него можно было проголосовать, как и должно быть. Это практически единственный правильный ответ в данной ситуации...   -  person Pavel Minaev    schedule 23.10.2009


Ответы (4)


Если ваша строка содержит все эти символы, кодовый набор должен быть основан на Unicode. При правильной реализации Unicode (глава 4 'Свойства символа') определяет свойства символа, в том числе то, является ли символ прописным, отображением нижнего регистра и т. д.

Учитывая эту преамбулу, функция towlower() из <wctype.h> является правильным инструментом для использования. Если это не работает, у вас есть проблема QoI (качество реализации), которую нужно обсудить с вашим поставщиком. Если вы обнаружите, что поставщик не отвечает, посмотрите на альтернативные библиотеки. В этом случае вы можете рассмотреть ICU (международные компоненты для Unicode).

person Jonathan Leffler    schedule 23.10.2009
comment
Отображения регистра Unicode, как указано в документе, на который вы ссылаетесь, по-прежнему частично зависят от локали. Цитата: SpecialCasing.txt — содержит дополнительные сопоставления регистра, которые сопоставляются более чем одному символу, например, «ß» к «SS». Также содержит сопоставления, зависящие от контекста, с флагами, чтобы отличать их от обычных сопоставлений, а также некоторые сопоставления, зависящие от локали. Таким образом, tolower не может не зависеть от локали. - person Pavel Minaev; 23.10.2009
comment
@Pavel Этот процесс называется нормализацией строк Unicode, который гарантирует, что ß и ss обрабатываются одинаково (в зависимости от выбранной формы нормализации), а Unicode содержит для этого нейтральные к языку алгоритмы, не игнорируя при этом желание локали или конкретного приложения. - person Abel; 23.10.2009
comment
@Abel: нормализация не является полным решением. Например, в некоторых латинских языках диакритические знаки исчезают на прописных буквах, а в других — нет. Невозможно сказать, если вы не знаете, на каком языке написан текст. Затем, конечно, есть печально известная проблема турецкого без точки i - вы хотите, чтобы İ было строчным в i и I в нижнем регистре ı для турецкого, но вы хотите, чтобы I чтобы в нижнем регистре до i для любого другого языка латинского алфавита. - person Pavel Minaev; 23.10.2009
comment
@Pavel: это отличная разработка, я полностью согласен. Нет, нормализация не идеальна, это скорее упрощенный метод грубой силы, но он помогает в большом количестве ситуаций. Вероятно, в обсуждение стоит включить ссылку на алгоритм сопоставления Unicode, в котором это обсуждается полностью (идет гораздо дальше, чем нижний/верхний регистр): unicode.org/reports/tr10 и сопоставление регистра Unicode: unicode.org/reports/tr21/tr21-5.html - person Abel; 26.10.2009
comment
@JonathanLeffler: отделение интенсивной терапии интересно, но, возможно, излишне. Я бы, вероятно, пошел на обработку UnicodeData.txt [скомпилировать в двоичный файл и отфильтровать ненужные части]. - person user877329; 24.05.2015

У вас есть неприятная проблема в руке. Японская локаль не поможет преобразовать немецкий язык и наоборот. Есть языки, в которых тоже нет концепции заглавных букв (я полагаю, toupper и друзья здесь не при чем). Итак, можете ли вы разбить свою строку на отдельные фрагменты слов одного и того же языка? Если вы можете, то вы можете преобразовать части и нанизать их.

person dirkgently    schedule 23.10.2009
comment
Японский и другие идеографические языки из Восточной Азии являются примерами языков, в основном без заглавных букв. - person Jonathan Leffler; 23.10.2009
comment
Мало того, отдельные языки могут иметь разные мнения о том, как конкретная буква должна быть прописной/нижней. Просто нет единого алгоритма, который бы правильно работал с любой случайной строкой Unicode без знания языка. - person Pavel Minaev; 23.10.2009
comment
Хотя я согласен с этой оценкой, Unicode включает в себя независимые от локали свойства верхнего и нижнего регистра, их использование описано в разделе 3.13 Операции с регистром по умолчанию, которые должны использоваться при отсутствии адаптации для определенных языков. , так говорит стандарт. - person Abel; 23.10.2009
comment
Оно делает. Проблема в том, что это верно, скажем, для 99% всех случаев, но вы ошибетесь в 1%. Что может быть проблемой, а может и не быть. В общем, это достаточно хорошо, когда вы используете его для таких вещей, как идентификаторы в коде и, возможно, даже имена файлов. - person Pavel Minaev; 23.10.2009
comment
@Pavel: Это означает, что вы не можете все время делать это правильно, но вы можете делать это последовательно все время. Я знаю, что строчные буквы «I» в «i» в турецком языке неверны, но если вы просто нормализуете строку для сравнения, а не распечатываете результат, это может работать нормально. - person David Thornley; 23.10.2009
comment
@David: это может не сработать. Допустим, у вас есть текст Diyarbakır в исходном документе, и пользователь ввел строку поиска DİYARBAKIR. Вы используете правила регистра Unicode по умолчанию для нижнего регистра обеих строк; первый становится диярбакыр, второй - диярбакыр. А теперь они не совпадают, а должны были бы, если текст турецкий. - person Pavel Minaev; 24.10.2009

Этот ответ SO показывает, как работать с фасетами для работы с несколькими локалями. Если это в Windows, вы можете рассмотреть возможность использования функций API win32, если вы можете работать с C++.NET (управляемый C++), вы можете использовать функции char.ToLower и string.ToLower, которые совместимы с Unicode.

person Abel    schedule 23.10.2009

Посмотрите _wcslwr_l в <wchar.h> (MSDN).

Вы должны иметь возможность запускать функцию на входе для каждой из локалей.

person Jon Seigel    schedule 23.10.2009
comment
Вы должны иметь возможность запускать функцию на входе для каждой из локалей. - что, если две локали в наборе отображают один и тот же символ по-разному? - person Pavel Minaev; 23.10.2009
comment
Как упоминалось в других комментариях, вы должны знать язык каждой части строки, чтобы избежать таких случаев. Там действительно нет обойти это. Я просто предлагаю использовать другую функцию, чтобы упростить решение проблемы с запуском операции в текущей локали. - person Jon Seigel; 23.10.2009