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

时间:2017-05-17 20:30:31

标签: java regex unicode

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

我理解&&表示"设置交叉点",\S是"非空格",但是什么是{{1 ,是否可以使用?

java.util.regex.Pattern documentation并未提及。列表中唯一类似的类是\p{C},但它们的行为不同:它们都匹配控制字符,但\p{Cntrl}匹配两次上面的U + FFFF上的Unicode字符,例如作为\p{C}

PILE OF POO

我在任何地方找到的唯一提法是here

  

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

但是,Java中似乎不存在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 `` } } ,并且未使用匹配的代码点。

我的Java版本信息:

\p{Other}

加分问题:原始模式$ 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) 的可能意图是什么?它发生在一个方法中,该方法在电子邮件中发送字符串之前对其进行验证:如果该模式匹配,则消息"无效字符串"被提出来了。

4 个答案:

答案 0 :(得分:20)

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

  

此课程符合Unicode Technical Standard #18: Unicode Regular Expression的第1级,加上RL2.1规范等效。

     

...

     可以使用可选前缀Is指定

类别:两者\ p {L}   和\ p {IsL}表示Unicode字母的类别。与脚本相同   和块,类别也可以使用关键字指定   general_category(或其缩写形式gc),如general_category = Lu或   GC =路。

     

支持的类别是The Unicode Standard中的类别   由Character类指定的版本。类别名称是那些   标准中定义的规范性和信息性。

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

它可能应该支持\p{Other},但显然它没有。

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

  

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

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

答案 1 :(得分:4)

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

  

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

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

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

答案 2 :(得分:1)

除了有效的双字母Unicode类别代码或开始Unicode类别代码的单个字母之外的任何内容都是非法的,因为Java仅支持Unicode类别的单字母和双字母缩写。这就是\p{Other}在这里不起作用的原因。

  

\p{C}U+FFFF上方的Unicode字符上匹配两次,例如PILE   POO。

右。 Java在内部对Unicode字符使用UTF-16编码,并编码为两个16位代码单元(0xD83D 0xDCA9),称为代理对(high surrogates),并且\p{C}分别匹配每一半

  

\p{Cs}\p{Surrogate}:UTF-16中代理对的一半   编码

您会在结果集中看到两个匹配项。

  

原始模式的可能意图是什么,[\\p{C}&&\\S]

我没有看到一个有效的理由,但似乎开发人员担心类别Other中的字符(比如在电子邮件主题中避免垃圾邮件goomojies),所以只是试图阻止它们。

答案 3 :(得分:0)

关于Bonus问题:表达式[\\ p {C} && \\ S]查找控制字符,但不包括空白字符(如Java中的制表符或换行符)。这些字符在常规邮件中没有任何价值,因此最好将它们过滤掉(或在这种情况下,将电子邮件内容声明为错误的)。请注意,仅双引号(\\)才需要转义表达式以进行Java处理。正确的正则表达式为:[\ p {C} && \\ S]