Подтвердить что ты не робот

Unicode-правильный заголовок в Java

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

Однако в библиотеке ICU существует чувствительный к языкам метод строкового имени (UCharacter#toTitleCase).


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

  • Найдите первый строковый символ в строке.
  • Если у него есть форма заголовка, отличная от его формы в верхнем регистре, используйте это.
  • В противном случае выполните строчный регистр, зависящий от локали, на этом первом символе и его комбинирующих символах.
  • Выполните локальный регистр нижнего регистра на остальной части строки.
  • Если языковой стандарт голландский, а первый одинарный символ - "I", за которым следует "j", верхний регистр "j".

Ответ 2

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

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

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

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

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

и

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

однако, следующее будет также приводить заголовок

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 с использованием символа toTitleCase.

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

Ответ 3

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

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

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