未记录的Java正则表达式字符类:\ p {C}

doc*_*red 28 java regex unicode

我在Java项目中发现了一个有趣的正则表达式: "[\\p{C}&&\\S]"

我理解这&&意味着"设置交集",并且\S是"非空白",但是什么是\p{C},并且可以使用吗?

java.util.regex.Pattern中的文件没有提到它.列表中唯一相似的类是\p{Cntrl},但它们的行为不同:它们都匹配控制字符,但在U + FFFF上方的Unicode字符上\p{C}匹配两次,例如PILE OF POO:

public class StrangePattern {
    public static void main(String[] argv) {

        // As far as I can tell, this is the simplest way to create a String
        // with code points above U+FFFF.
        String poo = new String(Character.toChars(0x1F4A9));

        System.out.println(poo);  // prints ``
        System.out.println(poo.replaceAll("\\p{C}", "?"));  // prints `??`
        System.out.println(poo.replaceAll("\\p{Cntrl}", "?"));  // prints ``
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经随处可见的唯一一提的是在这里:

\ p {C}或\ p {Other}:不可见的控制字符和未使用的代码点.

但是,\p{Other}Java中似乎不存在,并且匹配的代码点未被使用.

我的Java版本信息:

$ java -version
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
Run Code Online (Sandbox Code Playgroud)

奖金问题:原始模式的可能意图是"[\\p{C}&&\\S]"什么?它发生在一个方法中,该方法在电子邮件中发送字符串之前对其进行验证:如果该模式匹配,则会引发带有"无效字符串"消息的异常.

use*_*ica 22

隐藏在Unicode支持下的Pattern文档中,我们发现以下内容:

此类符合Unicode技术标准#18的第1级:Unicode正则表达式,以及RL2.1规范等效项.

...

可以使用可选前缀Is指定类别:\ p {L}和\ p {IsL}都表示Unicode字母的类别.与脚本和块相同,也可以使用关键字general_category(或其缩写形式gc)来指定类别,如general_category = Lu或gc = Lu.

支持的类别是由Character类指定的版本中的Unicode标准类别.类别名称是标准中定义的类别,包括规范性和信息性.

Unicode技术标准#18,我们发现它C被定义为匹配任何其他General_Category值,并且对此的支持是1级一致性要求的一部分.Java实现\p{C}是因为它声称符合UTS#18的第1级.


它可能应该支持\p{Other},但显然它不支持.

更糟糕的是,它违反了第1级一致性所要求的RL1.7,这要求通过代码点而不是代码单元进行匹配:

为满足此要求,实现应处理所有Unicode代码点,包括从U + FFFF到U + 10FFFF的值.特别是,在使用UTF-16的情况下,由前导代理和后跟代理组成的序列应作为匹配中的单个代码点处理.

\p{C}测试字符串中应该没有匹配项,因为您的测试字符串应该与General_Category = So(其他符号)而不是两个代理项匹配为单个表情符号代码点.


Tez*_*zra 7

根据https://regex101.com/, \p{C} 匹配

不可见的控制字符和未使用的代码点

(\ 必须被转义,因为 java 字符串,所以字符串 \\p{C} 是正则表达式 \p{C})

我猜这是一个“黑客字符串检查”,因为 \p{C} 可能永远不应该出现在有效(字符填充)字符串中,但作者应该留下评论作为他们检查的内容以及他们想要检查的内容通常是两种不同的东西。