5

我目前正在使用 Java 6(我没有迁移到 Java 7 的选项),并且我正在尝试使用 java.util.regex 包对包含 Unicode 字符的字符串进行模式匹配。

我知道 java.lang.String 支持补充字符(即代码点 > 0xFFFF 的字符)(从 Java 5 开始),但我没有看到一种简单的方法来对这些字符进行模式匹配。java.util.regex.Pattern 仍然只允许使用 4 位数字表示十六进制(例如 \uFFFF)

有谁知道我是否在这里缺少 API?

4

2 回答 2

7

我从未使用补充字符进行模式匹配,但我认为它就像将它们(在模式和字符串中)编码为两个 16 位数字(一个 UTF-16 代理对) \unnnn\ummmm 一样简单。 java.util.regex 应该足够聪明地将这两个数字(Java 字符)解释为模式和字符串中的单个字符(尽管 Java 仍将它们视为两个字符,作为字符串的元素)。

两个链接:

Java Unicode 编码

http://java.sun.com/developer/technicalArticles/Intl/Supplementary/

从最后一个链接(参考 Java 5):

java.util.regex 包已更新,因此模式字符串和目标字符串都可以包含补充字符,这些补充字符将作为完整的单元处理。

另请注意,如果您使用 UTF8 作为编码(用于源文件),您也可以直接编写它们(请参阅最后一个链接中的“在源文件中表示补充字符”部分)。

例如:

    String pat1 = ".*\uD840\uDC00{2}.*";
    String s1  = "HI \uD840\uDC00\uD840\uDC00 BYE";
    System.out.println(s1.matches(pat1) + " len=" + s1.length());

    String pat2 = ".*\u0040\u0041{2}.*";
    String s2 = "HI \u0040\u0041\u0040\u0041 BYE";
    System.out.println(s2.matches(pat2) + " len=" + s2.length());

这用 Java 6 编译,打印

true len=11
false len=11

这与上述一致。在第一种情况下,我们有一个单独的代码点,表示为一对代理 java 字符(两个 16 位字符,一个补充 Unicode 字符),{2}量词应用于这对(=代码点)。在第二个中,我们有两个不同的 BMP 字符,量词适用于最后一个 - 因此,不匹配。

但是请注意,字符串长度是相同的(因为 Java 测量字符串长度是计算 Java 字符,而不是 Unicode 代码点)。

于 2011-03-23T18:41:21.720 回答
2

最简单的解决方案是对源代码使用 UTF-8 编码。然后直接把字符放进去。您永远不必在任何程序中指定单独的代码单元。

然而,字符类仍然存在问题,因为 Java 暴露的 UTF-16 内部编码把它们弄乱了。在 JDK7 之前,您不能使用完整的 Unicode,即便如此,您也必须使用间接\x{HHHHH}表示法指定逻辑代码点。您仍然无法在 charclass 中拥有任何文字代码点,但您可以使用\x{H..H}.

不完美,但比以前好多了。UTF-16 始终是一种妥协。在内部使用 UTF-8 或 UTF-32 的系统没有这些限制。它们也永远不会让您指定与代码点不同的代码单元。

于 2011-04-16T00:05:31.967 回答