Java支持其正则表达式库中的非BMP Unicode字符(即代码点> 0xFFFF)?

时间:2011-03-23 18:06:26

标签: java regex unicode astral-plane

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

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

有人知道我在这里错过了一个API吗?

2 个答案:

答案 0 :(得分:6)

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

两个链接:

Java Unicode encoding

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}量词适用于该对(= codepoint)。在第二个中,我们有两个不同的BMP字符,量词适用于最后一个 - 因此,没有匹配。

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

答案 1 :(得分:2)

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

然而,字符类仍然存在问题,因为Java蹩脚暴露的UTF-16内部编码会使它们混乱。在JDK7之前不能使用完整的Unicode,即使这样,您也必须使用间接\x{HHHHH}表示法指定逻辑代码点。您仍然无法在charclass中包含任何文字代码点,但您可以使用\x{H..H}删除它。

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