java 8中的Pattern.matcher与sectionsign§不匹配§

时间:2015-07-10 12:33:34

标签: regex java-8

我有以下代码段:

private static final Pattern ESCAPER_PATTERN = Pattern.compile("[^a-zA-Z0-9\\p{P}\\s]*");

/**
 * @param args
 */
public static void main(String[] args)
{
    String unaccentedText = "Aa123 \\/*-+.=+:/;.,?u%µ£$*^¨-)ac!e§('\"e&€#²³~´][{^";
    System.out.println(ESCAPER_PATTERN.matcher(unaccentedText).replaceAll(""));         
}

当我使用JDK 7执行此操作时,我得到的输出是:

Aa123 \/*-.:/;.,?u%*-)ac!e('"e&#][{

当我用JDK 8执行相同操作时,我得到的输出是:

Aa123 \/*-.:/;.,?u%*-)ac!e§('"e&#][{

请注意,未使用JDK 8删除部分符号§。

请告诉我在JDK 8的情况下使用的正则表达式以匹配部分符号 - 以及jdks之间行为差异的原因。

1 个答案:

答案 0 :(得分:13)

Unicode移动了你的奶酪

U+00A7 SECTION SIGN中的字符§已从类别So(符号,其他)更改为类别Po(标点,其他):

  
      
  • UnicodeData.txt

         
        
    • U + 00A7,U + 00B6,U + 0F14,U + 1360和U + 10102从gc = So变为gc = Po。
    •   
  •   

由于Java在版本7中使用Unicode 6.1.0,在版本8中使用了Unicode 6.0.0,因此它解释了结果的不同之处。由于\p{P}现在属于标点符号类别,因此它在Java 8中与!匹配。

错误的解决方案

由于常规标点符号(如#""[^a-zA-Z0-9\\p{P}\\s&&[^\u00a7]]" ,...也属于Po类别,因此我们无法真正删除此子类别。

下一个明显的解决方案是使用字符集交集删除不需要的字符:

[^a-zA-Z0-9\p{P}\s&&[^§]]
Start. Start unanchored match (minLength=1)
Pattern.intersection. S ∩ T:
  Pattern.setDifference. S ∖ T:
    Pattern.setDifference. S ∖ T:
      Pattern.setDifference. S ∖ T:
        Pattern.setDifference. S ∖ T:
          CharProperty.complement. S̄:
            Pattern.rangeFor. U+0061 <= codePoint <= U+007A.
          Pattern.rangeFor. U+0041 <= codePoint <= U+005A.
        Pattern.rangeFor. U+0030 <= codePoint <= U+0039.
      DEBUG charProp: java.util.regex.Pattern$Category
    Ctype. POSIX (US-ASCII): SPACE
  CharProperty.complement. S̄:
    BitClass. Match any of these 1 character(s):
      §
java.util.regex.Pattern$LastNode
Node. Accept match

...但等一下,有Unicode 6.2.0,上面的正则表达式编译为:

[^a-zA-Z0-9\p{P}\s]

...解析为[^§][a-zA-Z0-9\p{P}\s]相交,而非([^§]"[[^a-zA-Z0-9\\p{P}\\s]\u00a7]" 相交)。

正确的解决方案

要解决上述问题,工作解决方案是:

[[^a-zA-Z0-9\p{P}\s]§]
Start. Start unanchored match (minLength=1)
Pattern.union. S ∪ T:
  Pattern.setDifference. S ∖ T:
    Pattern.setDifference. S ∖ T:
      Pattern.setDifference. S ∖ T:
        Pattern.setDifference. S ∖ T:
          CharProperty.complement. S̄:
            Pattern.rangeFor. U+0061 <= codePoint <= U+007A.
          Pattern.rangeFor. U+0041 <= codePoint <= U+005A.
        Pattern.rangeFor. U+0030 <= codePoint <= U+0039.
      DEBUG charProp: java.util.regex.Pattern$Category
    Ctype. POSIX (US-ASCII): SPACE
  BitClass. Match any of these 1 character(s):
    §
java.util.regex.Pattern$LastNode
Node. Accept match

编译为:

§

这次+正确地包含在角色类中,因此该符号将被删除。

请注意,我已删除量词以用于演示目的。请将量词添加回代码中的字符类,最好是一个或多个 {{1}}量词,而不是问题中使用的零或更多量词。