6

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

更新:@Reprogrammer 的建议(如下)是使用:

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());
    }

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

4

3 回答 3

5

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

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

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

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

例如,私人使用代码点可能出现在旨在使用字体显示的数据中,该字体具有分配给此类代码点的字形。这样的字体很笨拙,但它们确实存在,而且这种方法在形式上并不是不正确的。

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

于 2012-12-12T04:48:49.440 回答
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.
于 2012-12-10T06:36:36.713 回答
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>
于 2012-12-10T06:06:46.797 回答