Юникод-правильный заголовок в Java - PullRequest
30 голосов
/ 09 сентября 2011

Я просматривал весь StackOverflow в огромном количестве вопросов о том, как написать слово в Java, и ни один из них, похоже, не заботится о интернационализации, и на самом деле ни один из них не работает в международном контексте. Так вот мой вопрос.

У меня есть строка в Java, которая представляет слово - все символы isLetter (), без пробелов. Я хочу сделать первый символ заглавными, а остальные строчными. У меня есть слово моего слова под рукой.

Достаточно просто вызвать .substring (1) .toLowerCase (Locale) для последней части моей строки. Однако я не знаю, как получить правильный первый символ.

Первая проблема, с которой я столкнулся, связана с нидерландским языком, где «ij», являющийся орграфом, должно быть написано заглавными буквами. Я мог бы сделать это вручную, потому что я знаю об этом; теперь могут быть другие языки с такими вещами, о которых я не знаю, и я уверен, что Unicode скажет мне, если я задам хороший вопрос. Но я не знаю, как спросить.

Даже если вышеуказанная проблема решена, я все еще не могу должным образом обработать английский, турецкий и греческий языки, потому что Character поддерживает titlecase, но не локаль, а String поддерживает locales, но не titlecase.

Если я возьму кодовую точку и передам ее в Character.toTitleCase (), произойдет сбой, потому что нет способа передать локаль этому методу. Поэтому, если языковой стандарт системы - английский, но слово турецкое, а первый символ слова - «i», я получу «I» вместо «İ», и это неправильно. Теперь, если я возьму подстроку и использую .toUpperCase (Locale), это не получится, потому что это верхний регистр, а не заголовок. Поэтому, если слово греческое, я все равно получу неправильный символ.

Если у кого-нибудь есть полезные указатели, я буду рад их услышать.

Ответы [ 3 ]

7 голосов
/ 09 сентября 2011

Как и вы, мне не удалось найти подходящий метод в основном Java API.

Однако, похоже, существует чувствительный к локали метод string-title-case (UCharacter#toTitleCase) в библиотеке ICU .


При поиске источника соответствующих методов ICU (UCharacter#toTitleCase и UCaseProps#toUpperOrTitle), тамне похоже, чтобы было много особых случаев для локализаций, зависящих от локали, так что вы могли бы обойтись без следующего:

  1. Найти первый набранный символ в строке.
  2. Если у него есть форма регистра имени, отличная от формы в верхнем регистре, используйте это.
  3. В противном случае, выполните ввод регистрозависимого верхнего регистра для этого первого символа и его комбинирующих символов.
  4. Выполните чувствительный к локали нижний регистр для остальной части строки.
  5. Если локаль - нидерландский язык, а первым символом в регистре является «I», за которым следует «j», верхний регистр -"j".
5 голосов
/ 17 декабря 2016

Единственный двухсимвольный орграф, в котором оба символа пишутся с заглавной буквы одновременно и которые вы, вероятно, встретите в реальной программе, - это голландский IJ. Просто справьтесь, если локаль голландская. В худшем маловероятном сценарии, вам нужно будет добавить 1-2 случая позже, это не означает, что вы будете сталкиваться с новым орграфом с заглавными буквами каждый день, поэтому здесь не стоит фокусироваться на обобщении.

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

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

Например, рассмотрим символ dž . Форма в верхнем регистре - DŽ , а в форме заголовка - Dž :

System.out.println(Character.toUpperCase('\u01C4'));
DŽ

и

System.out.println(Character.toTitleCase('\u01C4'));
Dž

однако, следующее также даст название case

System.out.println(Character.toTitleCase(Character.toUpperCase('\u01C4')));
Dž

Таким образом, если вы преобразуете язык в верхний регистр перед регистром заглавия, вы получите правильный код, и при этом не будет проблем с использованием прецедента заглавия в результате, включая турецкий и т. Д.

System.out.println(Character.toTitleCase("dž".toUpperCase().charAt(0)));
System.out.println(Character.toTitleCase("i".toUpperCase(Locale.forLanguageTag("tr")).charAt(0)));
Dž
İ

Обратите внимание, что использование только регистра заглавия одного символа, если есть разница с его верхним регистром, неверно в общем случае.

Подведем итог:

  • Обработка голландского орграфа (или других орграфов, если вы столкнетесь с ними, я очень сомневаюсь, что в худшем случае это будет 1-2 случая для времени жизни программы).
  • Преобразовать необходимые символы в виде строки, используя locale и toUpperCase ()
  • Преобразование всех символов результата toUpperCase с использованием Character toTitleCase.

Обратите внимание, что все еще есть некоторые случаи с заглавными буквами, которые учитывают контекст, такие как ирландский префикс, английские имена ff и т. Д., Которые требуют больше, чем просто обработка символов / строк, но я сомневаюсь, что вам нужно обрабатывать их для генерации заголовка в программа.

3 голосов
/ 09 сентября 2011

Проблема в том, что различение прописных и строчных букв очень специфично для конкретного языка.У многих, может быть, у большинства языков такого нет.

В любом случае, есть Unicode faq: http://www.unicode.org/faq/casemap_charprop.html

.. и я предполагаю, что где-то есть таблица отображения, специфичная для Unicode (что-товот так ftp: //ftp.unicode.org/Public/UNIDATA/UnicodeData.txt).Так что, вероятно, лучше использовать собственный метод конвертации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...