Дифференцирование языков CJK (китайский, японский, корейский) на Android

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

  • Признать CJK как общую группу: я делаю вертикальный скрипт Mongolian TextView . Для этого мне нужно повернуть строку текста на 90 градусов, потому что глифы хранятся горизонтально в шрифте. Однако для языков CJK мне нужно повернуть их назад, чтобы они были написаны в правильной ориентации, но просто укладывались друг на друга по линии.
  • Дифференцируйте CJK на определенные языки: я также делаю монгольский словарь, и когда пользователи вводят символ CJK для поиска, я бы хотел автоматически распознавать язык. Поскольку китайские иероглифы также используются японцами и корейцами, я предполагаю, что я не смогу полностью выполнить это, но я хочу сделать это в максимальной степени, что позволяет кодирование.

На лингвистической стороне подкатегории, о которых я знаю, являются

  • Китайские традиционные персонажи
  • Китайские упрощенные символы
  • Японский кандзи (китайские иероглифы)
  • Японский Хирагана (родной алфавит)
  • Японская катакана (алфавит для написания иностранных слов)
  • Корейский хангул (фонетический)
  • Корейский Hanja (китайские персонажи)

Для полноты китайские символы также используются на вьетнамском языке (поэтому CJK также называется CJKV). Для моих текущих целей мне не нужно беспокоиться об этом, но это может быть будущее. Я также игнорирую румынские скрипты, такие как китайский пиньинь или японский ромаджи . Они будут обрабатываться так же, как английский и монгольский в TextView (т. Е. Повернуты на 90 градусов с остальной частью строки). Bopomofo, используемый на Тайване, также может рассматриваться в будущем, но пока я его не буду игнорировать. См. Также здесь и здесь для примеров языков.

Я видел ряд связанных вопросов, которые обычно имеют дело с одним конкретным языком на Java или Android, но нет всеобъемлющего вопроса с каноническим ответом. Другие вопросы более общие для Unicode, но не говорят, как это сделать в Java и Android. Вот некоторые из конкретных.

  • Как проверить, является ли данный текст английским или китайским в андроиде?
  • Как я могу обнаружить японский текст в строке Java?
  • Проверьте, содержит ли строка символы CJK (китайский)
  • Используйте регулярное выражение для соответствия любому китайскому символу в кодировке utf-8
  • Тестирование для японских / китайских символов в строке
  • Различные представления кодов Unicode на японском и китайском языках
  • Проверьте, является ли символ традиционным китайским в Big-5 (Java)?
  • Юникод-символы, необходимые для японского, корейского и китайского языков
  • Разделяют ли те же китайские символы, что и cjk, имеют одинаковое значение для юникода?
  • Каков полный диапазон для китайских иероглифов в Юникоде?

Поэтому мой вопрос: насколько я могу различать языки CJK с использованием кодовых страниц Unicode и как я могу проверить их на Android? Я видел несколько новых тестов на Java и Android, и, хотя это полезно знать, мне также необходимо поддерживать старые Android-устройства.

Unicode

CJK (и CJKV) в Unicode относится к Han Ideographs, то есть к китайским иероглифам (汉字), используемым на китайском, японском, корейском и вьетнамском языках. Для именования Unicode это не относится к фонетическим письменным сценариям, таким как японская Katakana и Hiragana или корейский Hangul. Идеи Хана, как говорят, унифицированы. Под этим подразумевается, что для каждого идеографа имеется только один код Unicode, независимо от того, на каком языке он используется.

Это означает, что Unicode (и, наоборот, Android / Java) не дает возможности определить язык, основанный только на одной идеограмме. Даже китайские упрощенные / традиционные символы не легко отличаются от кодировки. Это та же идея, что и не знать, принадлежит ли символ «а» английскому, французскому или испанскому. Для определения этого требуется больше контекста.

Тем не менее, вы можете использовать кодировку Unicode для определения японского Hiragana / Katakana и корейского хангула. И присутствие таких персонажей было бы хорошим свидетельством того, что соседние Хан-Идеографы принадлежат одному и тому же языку.

Android

Вы можете найти код в некотором индексе с помощью

 int codepoint = Character.codePointAt(myString, offset) 

И если вы хотите итерации по кодовым точкам в строке :

 final int length = myString.length(); for (int offset = 0; offset < length; ) { final int codepoint = Character.codePointAt(myString, offset); // use codepoint here offset += Character.charCount(codepoint); } 

Когда у вас есть код, вы можете посмотреть, в каком блоке кода он находится

 Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint); 

И тогда вы можете использовать код для проверки идеограммы или языка.

Дальневосточные

Сканирование блоков кода Unicode, я думаю, что они охватывают все идеограммы CJK. Если я пропустил любой, то не стесняйтесь редактировать мой ответ или оставить комментарий.

 private boolean isCJK(int codepoint) { Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint); return ( Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS.equals(block)|| Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A.equals(block) || Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B.equals(block) || Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C.equals(block) || // api 19 Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D.equals(block) || // api 19 Character.UnicodeBlock.CJK_COMPATIBILITY.equals(block) || Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS.equals(block) || Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS.equals(block) || Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT.equals(block) || Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT.equals(block) || Character.UnicodeBlock.CJK_STROKES.equals(block) || // api 19 Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION.equals(block) || Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS.equals(block) || Character.UnicodeBlock.ENCLOSED_IDEOGRAPHIC_SUPPLEMENT.equals(block) || // api 19 Character.UnicodeBlock.KANGXI_RADICALS.equals(block) || Character.UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS.equals(block)); } 

Те, у кого есть комментарии (прокрутка вправо), доступны только с уровня API 19. Однако их можно было бы безопасно удалить, если вам нужно поддерживать более ранние версии, поскольку они используются редко. Кроме того, Unicode определяет расширение CJK E, но на момент написания этой статьи он не поддерживается в Android / Java. Если вам обязательно нужно включить все, то вы можете напрямую сравнить коды с диапазонами блоков Unicode. Этот сайт является удобным местом для их просмотра. Вы также можете увидеть их на сайте Unicode .

Если вам не нужно поддерживать ниже API 19, то isIdeographic делает тест очень простым (хотя я не знаю, вернет ли он точно такие же соответствия, как и метод выше).

 private boolean isCJK(int codepoint) { return Character.isIdeographic(codepoint); } 

Или этот для API 24+:

 private boolean isCJK(int codepoint) { return (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN); } 

Японский

Для тестирования Hiragana или Katakana это должно работать нормально:

 private boolean isJapaneseKana(int codepoint) { Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint); return ( Character.UnicodeBlock.HIRAGANA.equals(block) || Character.UnicodeBlock.KATAKANA.equals(block) || Character.UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS.equals(block)); } 

Или это, если вы поддерживаете API 24+:

 private boolean isJapaneseKana(int codepoint) { return (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HIRAGANA || Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.KATAKANA); } 

Корейский

Чтобы проверить Hangul на более низких API, вы можете использовать

 private boolean isKoreanHangul(int codepoint) { Character.UnicodeBlock block = Character.UnicodeBlock.of(codepoint); return (Character.UnicodeBlock.HANGUL_JAMO.equals(block) || Character.UnicodeBlock.HANGUL_JAMO_EXTENDED_A.equals(block) || // api 19 Character.UnicodeBlock.HANGUL_JAMO_EXTENDED_B.equals(block) || // api 19 Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO.equals(block) || Character.UnicodeBlock.HANGUL_SYLLABLES.equals(block)); } 

Удалите строки, обозначенные API 19, если необходимо.

Или для API 24+:

 private boolean isKoreanHangul(int codepoint) { return (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HANGUL); } 

Дальнейшее изучение

  • Юникодские восточноазиатские скрипты
  • Часто задаваемые вопросы по Unicode CJK
  • Часто задаваемые вопросы по Unicode
  • Некоторые исходные коды, которые показывают, как работает Character.UnicodeScript
  • Унифицированные идеограммы CJK