问题由来:
在代码中看到了Pattern.compile("\\p{P}")
,用来识别符号,但是这个正则表达式却不匹配加号+
,所以\p{P}
到底是什么意思呢
谷歌了一下,找到StackOverflow上有人问了一模一样的问题
可是这个问题被关掉了,理由是问题重复,贴出了另一个解释所有正则表达式含义的参考回答
nice try,给出正则表达式的参考回答,此举可以减少重复零散的提问
问题是这个参考回答里面根本没有说\p{P}
到底是什么意思
(似乎在查正则表达式的时候总会遇到类似的问题,然后每次都会归因于自己没学好正则)
再回去看StackOverflow上的回答,有人贴出了Java文档,说这篇文档中有解释
问题是,并没有啊
文档中提到了\p{Punct}
,是下列符号之一:!"#$%&'()*+,-./:;<=>?@[]^_`{|}~,很好,定义非常清晰。
\p{P}
会是\p{Punct}
的缩写吗,可是\p{P}
是不会匹配+
的,而\p{Punct}
的定义中是包含+
的
文档中还提到了\p{Print}
,是可打印字符[\p{Graph}\x20]
,其中\p{Graph}
是[\p{Alnum}\p{Punct}]
,其中[\p{Lower}\p{Upper}]
,其中\p{Lower}
和\p{Upper}
分别是[a-z]
和[A-Z]
。好家伙,环环相扣。
所以\p{P}
是\p{Punct}
还是\p{Print}
呢,反正Java文档里面没说。
测试一下
Pattern.matches("\\p{P}", "+");
Pattern.matches("\\p{Punct}", "+");
结果分别是false
和true
,显然\p{P}
和\p{Punct}
不是一回事
再回到StackOverflow,在Java文档的回复下还有两条回复
If I search the Javadocs I don’t find \p{P} just \p{Punctuation} and \p{Print}. Similarly I searched the referenced answer which is already supposed to answer this question and also don’t find a reference to \p{P}
我查找了Java文档,没找到\p{P}
,只找到\p{Punctuation}
和\p{Print}
。同样,我查找了参考回答,那里面本应有这个问题的答案吧?但是我没找到对于\p{P}
的解释
The linked question (“What does this regex mean?”) doesn’t specifically mention the punctuation Unicode category, but does state that \p is for Unicode categories, which addresses what \p means (which is asked in this question). Whether it’s a duplicate depends in part on whether this question is primarily asking for an explanation for \p, or what the ‘P’ category is (in which case, this question is actually asking 2 questions, one of which is a duplicate).
链接中的问题(“这个正则表达式是什么意思”)并未明确提及Unicode的标点目录,不过确实说到了\p
表示Unicode目录,这解决了\p
是什么意思的问题(这是本问题中问到的)。这个问题是否重复部分取决于这个问题首先是要求解释\p
,还是要求解释“P目录”是什么(在这种情况下,这个问题实际上是提出了两个问题,其中一个是重复的)。
看来不止我有同样的疑问。
再看这个问题的关闭记录,里面提到StackOverflow社区重新审核了是否要重新开启这个问题,结论是,还是让它保持关闭状态吧,当初关闭它的理由不变。怎么就感觉这个问题这么冤呢?
这时我还发现idea居然能识别\p{P}
和\p{Punct}
(这个提示也说明\p{P}
不是\p{Print}
)
得,Punctuation和Punctuation characters还有区别
既然谁讲也讲不清楚,那就暴力试验一下,\p{P}
和\p{Punct}
到底会匹配哪些字符
public static final Pattern P = Pattern.compile("\\p{P}");
public static final Pattern PUNCT = Pattern.compile("\\p{Punct}");
public static void main(String[] args) {
StringBuilder psb = new StringBuilder();
StringBuilder punctsb = new StringBuilder();
// 穷举所有码点
for (int i = Character.MIN_CODE_POINT; i < Character.MAX_CODE_POINT; i++) {
String c = String.valueOf(Character.toChars(i));
if (P.matcher(c).find()) {
psb.append(c);
}
if (PUNCT.matcher(c).find()) {
punctsb.append(c);
}
}
System.out.println(psb);
System.out.println(punctsb);
}
输出结果如下,说来差别也是蛮大的
!"#%&'()*,-./:;?@[\]_{}¡§«¶·»¿;·՚՛՜՝՞՟։֊־׀׃׆׳״؉؊،؍؛؞؟٪٫٬٭۔܀܁܂܃܄܅܆܇܈܉܊܋܌܍߷߸߹࠰࠱࠲࠳࠴࠵࠶࠷࠸࠹࠺࠻࠼࠽࠾࡞।॥॰૰෴๏๚๛༄༅༆༇༈༉༊་༌།༎༏༐༑༒༔༺༻༼༽྅࿐࿑࿒࿓࿔࿙࿚၊။၌၍၎၏჻፠፡።፣፤፥፦፧፨᐀᙭᙮᚛᚜᛫᛬᛭᜵᜶។៕៖៘៙៚᠀᠁᠂᠃᠄᠅᠆᠇᠈᠉᠊᥄᥅᨞᨟᪠᪡᪢᪣᪤᪥᪦᪨᪩᪪᪫᪬᪭᭚᭛᭜᭝᭞᭟᭠᯼᯽᯾᯿᰻᰼᰽᰾᰿᱾᱿᳀᳁᳂᳃᳄᳅᳆᳇᳓‐‑‒–—―‖‗‘’‚‛“”„‟†‡•‣․‥…‧‰‱′″‴‵‶‷‸‹›※‼‽‾‿⁀⁁⁂⁃⁅⁆⁇⁈⁉⁊⁋⁌⁍⁎⁏⁐⁑⁓⁔⁕⁖⁗⁘⁙⁚⁛⁜⁝⁞⁽⁾₍₎〈〉❨❩❪❫❬❭❮❯❰❱❲❳❴❵⟅⟆⟦⟧⟨⟩⟪⟫⟬⟭⟮⟯⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌⦍⦎⦏⦐⦑⦒⦓⦔⦕⦖⦗⦘⧘⧙⧚⧛⧼⧽⳹⳺⳻⳼⳾⳿⵰⸀⸁⸂⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌⸍⸎⸏⸐⸑⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜⸝⸞⸟⸠⸡⸢⸣⸤⸥⸦⸧⸨⸩⸪⸫⸬⸭⸮⸰⸱⸲⸳⸴⸵⸶⸷⸸⸹⸺⸻、。〃〈〉《》「」『』【】〔〕〖〗〘〙〚〛〜〝〞〟〰〽゠・꓾꓿꘍꘎꘏꙳꙾꛲꛳꛴꛵꛶꛷꡴꡵꡶꡷꣎꣏꣸꣹꣺꤮꤯꥟꧁꧂꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌꧍꧞꧟꩜꩝꩞꩟꫞꫟꫰꫱꯫﴾﴿︐︑︒︓︔︕︖︗︘︙︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀﹁﹂﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌﹍﹎﹏﹐﹑﹒﹔﹕﹖﹗﹘﹙﹚﹛﹜﹝﹞﹟﹠﹡﹣﹨﹪﹫!"#%&'()*,-./:;?@[\]_{}⦅⦆。「」、・𐄀𐄁𐄂𐎟𐏐𐡗𐤟𐤿𐩐𐩑𐩒𐩓𐩔𐩕𐩖𐩗𐩘𐩿𐬹𐬺𐬻𐬼𐬽𐬾𐬿𑁇𑁈𑁉𑁊𑁋𑁌𑁍𑂻𑂼𑂾𑂿𑃀𑃁𑅀𑅁𑅂𑅃𑇅𑇆𑇇𑇈𒑰𒑱𒑲𒑳
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
idea还有自动补全提示
这么看来Unicode确实有很多用字母或缩写表示的category,理应是存在一个文档的,不然idea怎么认识呢,不然Java怎么会去实现呢
或许关键词是Unicode category
回到StackOverflow的参考回答,在其中找到了一个叫Unicode categories的链接,链接到了另一个问题:Unicode category L是什么
其中一个回答贴出了一个链接,其中列出了所有的Unicode categories
谷歌一下Unicode categories,找到了维基百科的解释
这些名字越看越眼熟,不就是我两年前看过的东西么,淦
总结一下
\p{P}是Unicode定义的,是一个Unicode目录,表示所有的符号,可以细分为Pc、Pd、Pe等等
\p{Punct}是Java定义的,是下列符号之一:!"#$%&'()*+,-./:;<=>?@[]^_`{|}~
那么还有最后一个问题
为什么Unicode P目录下不包含加号+
?
其实也没有为什么,反正Unicode把加号归类到S目录下了(S for Symbol),具体来说是Sm目录(Symbol, math)
刨根问底结束