在 Android 中区分 CJK 语言(中文、日语、韩语)
Differentiating CJK languages (Chinese, Japanese, Korean) in Android
我希望能够识别中文、日文和韩文的书面字符,既可以作为一般语言,也可以作为细分语言。这些是原因:
- 将CJK识别为一个通用组:我正在制作竖排蒙古文
TextView
。为此,我需要将文本行旋转 90 度,因为字形是水平存储在字体中的。但是,对于 CJK 语言,我需要将它们再次旋转回来,以便它们以正确的方向书写,但只是彼此堆叠在一起。
- 将CJK区分为特定语言:我也在制作蒙古语词典,当用户输入CJK字符进行查找时,我想自动识别该语言。因为汉字也被日本人和韩国人使用,我猜我不能完全做到这一点,但我想在编码允许的最大程度上做到这一点。
在语言方面,我知道的子类别是
- Chinese traditional characters
- Chinese simplified characters
- Japanese Kanji(汉字)
- Japanese Hiragana(本地字母表)
- Japanese Katakana(写外来词的字母表)
- Korean Hangul(注音)
- Korean Hanja(汉字)
为了完整起见,Vietnamese (so CJK is also called CJKV). For my current purposes I don't need to worry about it, but it could be a future consideration. I am also ignoring romanized scripts like Chinese pinyin or Japanese romaji. They will be handled the same as English and Mongolian in the TextView (ie, rotated 90 degrees with the rest of the line). Bopomofo used in Taiwan could also be a future consideration, but I will ignore it for now. See also here and here中也使用了汉字作为语言示例。
我已经看到许多相关问题通常涉及 Java 或 Android 中的一种特定语言,但没有包含规范答案的总体问题。其他问题对 Unicode 更通用,但在 Java 和 Android 中没有说明如何做。下面是一些具体的。
- How to check whether given text is english or chinese in android?
- How can I detect japanese text in a Java string?
- Check if string contains CJK (chinese) characters
- Use regular expression to match ANY Chinese character in utf-8 encoding
- Testing for Japanese/Chinese Characters in a string
- Different representation of unicode code points in Japanese and chinese
- Check if a character is Traditional Chinese in Big-5 (Java)?
- Unicode characters necessary for Japanese, Korean, and Chinese
- What's the complete range for Chinese characters in Unicode?
所以我的问题是,使用 Unicode 代码点可以在多大程度上区分 CJK 语言以及如何在 Android 中测试它们?我在 Java 和 Android 中看到了一些较新的测试,虽然了解这些很有用,但我还需要支持较旧的 Android 设备。
Unicode
Unicode中的CJK(和CJKV)是指Han Ideographs,即中文、日文、韩文、越南文使用的汉字。对于Unicode脚本命名,它不是指的是日语片假名和平假名或韩语韩文等注音文字。据说汉意图是统一的。他们的意思是每个表意文字只有一个 Unicode 代码点,无论它使用哪种语言。
这意味着 Unicode(反之 Android/Java)无法提供仅基于单个表意文字来确定语言的方法。即使是中文 Simplified/Traditional 字符也不容易从编码中区分出来。这与无法知道字符 "a" 属于英语、法语还是西班牙语是一样的。需要更多上下文才能确定。
但是,您可以使用 Unicode 编码来确定日文 Hiragana/Katakana 和韩文。并且这些字符的存在将很好地表明附近的汉表意文字属于同一语言。
Android
您可以通过
在某个索引处找到代码点
int codepoint = Character.codePointAt(myString, offset)
如果你想 iterate through the codepoints in a string:
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 块范围进行比较。 This site is a convenient place to browse them. You can also see them at the Unicode site.
如果API19以下不需要支持,那么isIdeographic
测试起来很简单(虽然不知道returns是否完全一样匹配如上方法)。
private boolean isCJK(int codepoint) {
return Character.isIdeographic(codepoint);
}
或者这个 API 24+:
private boolean isCJK(int codepoint) {
return (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN);
}
日语
对于测试平假名或片假名,这应该可以正常工作:
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);
}
韩语
要在较低的 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 East Asian scripts
- Unicode CJK FAQs
- Unicode Korean FAQs
- Some source code 展示了
Character.UnicodeScript
的工作原理
- CJK Unified Ideographs
我希望能够识别中文、日文和韩文的书面字符,既可以作为一般语言,也可以作为细分语言。这些是原因:
- 将CJK识别为一个通用组:我正在制作竖排蒙古文
TextView
。为此,我需要将文本行旋转 90 度,因为字形是水平存储在字体中的。但是,对于 CJK 语言,我需要将它们再次旋转回来,以便它们以正确的方向书写,但只是彼此堆叠在一起。 - 将CJK区分为特定语言:我也在制作蒙古语词典,当用户输入CJK字符进行查找时,我想自动识别该语言。因为汉字也被日本人和韩国人使用,我猜我不能完全做到这一点,但我想在编码允许的最大程度上做到这一点。
在语言方面,我知道的子类别是
- Chinese traditional characters
- Chinese simplified characters
- Japanese Kanji(汉字)
- Japanese Hiragana(本地字母表)
- Japanese Katakana(写外来词的字母表)
- Korean Hangul(注音)
- Korean Hanja(汉字)
为了完整起见,Vietnamese (so CJK is also called CJKV). For my current purposes I don't need to worry about it, but it could be a future consideration. I am also ignoring romanized scripts like Chinese pinyin or Japanese romaji. They will be handled the same as English and Mongolian in the TextView (ie, rotated 90 degrees with the rest of the line). Bopomofo used in Taiwan could also be a future consideration, but I will ignore it for now. See also here and here中也使用了汉字作为语言示例。
我已经看到许多相关问题通常涉及 Java 或 Android 中的一种特定语言,但没有包含规范答案的总体问题。其他问题对 Unicode 更通用,但在 Java 和 Android 中没有说明如何做。下面是一些具体的。
- How to check whether given text is english or chinese in android?
- How can I detect japanese text in a Java string?
- Check if string contains CJK (chinese) characters
- Use regular expression to match ANY Chinese character in utf-8 encoding
- Testing for Japanese/Chinese Characters in a string
- Different representation of unicode code points in Japanese and chinese
- Check if a character is Traditional Chinese in Big-5 (Java)?
- Unicode characters necessary for Japanese, Korean, and Chinese
- What's the complete range for Chinese characters in Unicode?
所以我的问题是,使用 Unicode 代码点可以在多大程度上区分 CJK 语言以及如何在 Android 中测试它们?我在 Java 和 Android 中看到了一些较新的测试,虽然了解这些很有用,但我还需要支持较旧的 Android 设备。
Unicode
Unicode中的CJK(和CJKV)是指Han Ideographs,即中文、日文、韩文、越南文使用的汉字。对于Unicode脚本命名,它不是指的是日语片假名和平假名或韩语韩文等注音文字。据说汉意图是统一的。他们的意思是每个表意文字只有一个 Unicode 代码点,无论它使用哪种语言。
这意味着 Unicode(反之 Android/Java)无法提供仅基于单个表意文字来确定语言的方法。即使是中文 Simplified/Traditional 字符也不容易从编码中区分出来。这与无法知道字符 "a" 属于英语、法语还是西班牙语是一样的。需要更多上下文才能确定。
但是,您可以使用 Unicode 编码来确定日文 Hiragana/Katakana 和韩文。并且这些字符的存在将很好地表明附近的汉表意文字属于同一语言。
Android
您可以通过
在某个索引处找到代码点int codepoint = Character.codePointAt(myString, offset)
如果你想 iterate through the codepoints in a string:
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 块范围进行比较。 This site is a convenient place to browse them. You can also see them at the Unicode site.
如果API19以下不需要支持,那么isIdeographic
测试起来很简单(虽然不知道returns是否完全一样匹配如上方法)。
private boolean isCJK(int codepoint) {
return Character.isIdeographic(codepoint);
}
或者这个 API 24+:
private boolean isCJK(int codepoint) {
return (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN);
}
日语
对于测试平假名或片假名,这应该可以正常工作:
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);
}
韩语
要在较低的 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 East Asian scripts
- Unicode CJK FAQs
- Unicode Korean FAQs
- Some source code 展示了
Character.UnicodeScript
的工作原理 - CJK Unified Ideographs