如何确定Unicode字符是否有效

时间:2012-12-10 04:04:06

标签: java unicode internationalization icu

我想要一个可以指示Unicode点是否有效的算法或库。例如,U+F8F8似乎不是有效的Unicode字符,但被描述为"PRIVATE_USE_AREA"。我发现ICU - 这是一个很好/最好的解决方案吗?

更新:@重编程师的建议(见下文)是使用:

CoderResult call(CharsetDecoderICU decoder, Object context, 
     ByteBuffer source, CharBuffer target, IntBuffer offsets, 
     char[] buffer, int length, CoderResult cr)
This function is called when the bytes in the source cannot be handled, 
    and this function is meant to handle or fix the error if possible.

感谢。这看起来比我希望的更复杂 - 也许这比我想象的更复杂。 (问题包括'<Non Private Use High Surrogate, First>' (U+D800)等点(我假设)只有在跟着至少一个代码点后才有效。

更新:@Jukka写道:

  

定义“有效”。私有使用代码点根据Unicode有效   标准,它没有任何分配给它的字符   标准。代理代码点不是有效的字符数据,但是   代理代码单元可以在UTF-16中使用。 Java字符串是一个   代码单元序列,而不是字符;任何代码单元都可能出现   在那里,但是当你将字符串作为字符处理时,它应该符合   对字符的Unicode要求。 - Jukka K. Korpela

我同意定义“有效”非常重要。我从FileFormat.Info网站上获取了使用声明:

 U+F8F8 is not a valid unicode character.

这似乎是一个相当权威的网站所以我使用了他们的术语。也许他们有点不精确

更新: 我已经尝试了@ Ignacio的Python到Java但是失败了。我写了

public void testUnicode() {
        Pattern pattern = Pattern.compile("\\p{Cn}");
        System.out.println("\\u0020 "+pattern.matcher("\u0020").matches());
        System.out.println("A "+pattern.matcher("A").matches());
        System.out.println("\\uf8f8 "+pattern.matcher("\uf8f8").matches());
    }

统一返回false,即使是“有效”的Unicode字符。我也找不到记录\p{Cn}

3 个答案:

答案 0 :(得分:4)

您在@ IgnacioVazquez-Abrams对答案的评论中描述的方法是正确的,使用匹配"\\p{Cn}"等模式来测试一般类别(gc)属性。但是对于U + F8F8,这种特定的匹配正确地产生了错误,因为这个角色的类别不是Cn而是Cs(其他,代理)。如果你测试例如对于U + FFFF,你会成真。

主要类C中的Unicode类别(类别名称以C开头)是:

  • 抄送:其他,控制;控制字符,例如回车
  • Cf:其他,格式;例如软连字符(不可见,但可能影响格式化)
  • Cs:其他,代理人;在字符数据中无效,但可能成对出现在Java字符串中(这是一串代码单元,而不是字符)
  • Co:其他,私人使用;在字符数据中有效,但Unicode标准没有为其分配字符,并且不应在信息交换中使用,除非通过私有赋值(为代码点指定一些含义)
  • Cn:其他,未分配;这可能意味着代码点永久地表示为非字符,或者只是未分配,例如尚未分配(但可能会分配给Unicode未来版本中的字符)

因此,在测试有效性时,应拒绝Cn(保留在Unicode标准更改时可能导致拒绝有效字符);在测试代​​码点时应该拒绝Cs,但是当处理Java字符串时,当第一个字符串是高代理字符串时,你应该接受一对Cs字符,而第二个字符串是低代理字符串(假设您希望接受基本多语言平面之外的字符) );和Co的处理取决于您是否希望将私人使用代码点视为有效。

私人使用代码点可能出现在例如要使用具有分配给此类代码点的字形的字体显示的数据中。这些字体是kludgy,但它们存在,而且这种方法并非正式错误。

其他主要类中的Unicode代码点将被视为无可置疑的字符。这并不意味着应用程序需要接受它们,只是它们有效地表示字符。

答案 1 :(得分:1)

尝试使用String.codePointAt
这是API:

int java.lang.String.codePointAt(int index)



codePointAt
public int codePointAt(int index)
Returns the character (Unicode code point) at the specified index. 
   The index refers to char values (Unicode code units) and ranges from 0 to length() - 1. 
If the char value specified at the given index is in the high-surrogate range, the 
    following index is less than the length of this String, and the char value at the 
    following index is in the low-surrogate range, then the supplementary code point 
    corresponding to this surrogate pair is returned. Otherwise, the char value at the
    given index is returned. 


Parameters:
index - the index to the char values 
Returns:
the code point value of the character at the index 
Throws: 
IndexOutOfBoundsException - if the index argument is negative or not less than the 
    length of this string.

答案 2 :(得分:0)

与“Cn”Unicode属性匹配表示Unicode字符无效。 Python中的一个例子(可以很容易地转换为Java):

>>> regex.match(r'\p{Cn}', u'\ud800')
<_regex.Match object at 0x7f6d5552c120>
>>> regex.match(r'\p{Cn}', u'a')
>>> regex.match(r'\p{Cn}', u'\uf8f8')
<_regex.Match object at 0x7f6d5552c198>