【问题标题】:How to determine if a Unicode character is valid如何确定 Unicode 字符是否有效
【发布时间】:2012-11-27 12:07:11
【问题描述】:

我想要一个可以指示 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} 记录。

【问题讨论】:

  • 你试过CharsetCallback.Decoder icu-project.org/apiref/icu4j/com/ibm/icu/charset/…吗?
  • 定义“有效”。根据 Unicode 标准,私人使用代码点是有效的,它只是没有在标准中分配任何字符。代理 code point 不是有效的字符数据,但代理 code units 可以在 UTF-16 中使用。 Java 字符串是一系列代码单元,而不是字符;任何代码单元都可能出现在那里,但是当您将字符串作为字符处理时,它应该符合字符的 Unicode 要求。
  • @Jukka 这非常有用。已将其复制到文本中。

标签: java unicode internationalization icu


【解决方案1】:

与“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>

【讨论】:

  • 这不是一个很有帮助的回复,因为我不理解 Python 的“Cn”Unicode 属性,而且(至少对我而言)它不能轻易转换为 Java,因为我不明白它根本没有。 “Cn”是一组定义 Unicode 的正则表达式吗?
  • 不是 Python 的,而是 Unicode's。只需将其推入Pattern
  • 试过了: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 (对不起格式)
  • 前两个应该返回 false,因为它们是有效字符。不知道为什么是第三个;也许你的 JVM 的 Unicode 数据库已经过时了(甚至是错误的?)。
【解决方案2】:

尝试使用 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.

【讨论】:

  • 这看起来很有用,我会试试看。 (格式化以便于阅读)
【解决方案3】:

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

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

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

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-21
  • 2011-06-01
  • 2019-12-18
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2023-03-21
相关资源
最近更新 更多