Java 正则表达式:什么是组合符号?

Java 正则表达式:什么是组合符号?,java,regex,unicode,Java,Regex,Unicode,众所周知,以下代码可以将重音字符转换为纯文本: Normalizer.normalize(text, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); 我用这个方法替换了我的“手工制作”方法,但是我需要理解replaceAll的“regex”部分 1) 什么是“不可组合的关键标记”? 2) 文件在哪里?(还有相似的吗?) 谢谢。\p{InCombiningDiacriticalMarks}是一个U

众所周知,以下代码可以将重音字符转换为纯文本:

Normalizer.normalize(text, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
我用这个方法替换了我的“手工制作”方法,但是我需要理解replaceAll的“regex”部分

1) 什么是“不可组合的关键标记”?
2) 文件在哪里?(还有相似的吗?)


谢谢。

\p{InCombiningDiacriticalMarks}
是一个Unicode块属性。在JDK7中,您将能够使用两部分表示法
\p{Block=CombiningDiacriticalMarks}
编写它,这对读者来说可能更清楚。这是有案可查的

它的意思是代码点落在一个特定的范围内,一个块,该块已被分配用于该名称下的事物。这是一种糟糕的方法,因为不能保证该范围内的代码点是或不是任何特定的东西,也不能保证该块外的代码点本质上不是同一个字符

例如,在
\p{Latin_1_Supplement}
块中有拉丁字母,如é、U+00E9。然而,有些东西也不是拉丁字母。当然,到处都是拉丁字母

积木几乎从来都不是你想要的

在本例中,我怀疑您可能希望使用属性
\p{Mn}
,也称
\p{nonspace\u Mark}
。组合_Diacriticals块中的所有代码点都属于这种类型。还有(从Unicode 6.0.0开始)1087个非空格_标记不在该块中

这与检查
\p{Bidi\u Class=nonspace\u Mark}
几乎相同,但不完全相同,因为该组还包括封闭标记
\p{Me}
。如果两者都需要,如果您使用的是默认Java正则表达式引擎,则可以说
[\p{Mn}\p{Me}]
,因为它只提供对General_Category属性的访问

<>你必须使用JNI来访问ICU C++ +正则表达式库,这样谷歌就可以访问诸如“代码> \p{bc= nsM}} /Code >,因为现在只有ICU和Perl提供了对所有Unicode属性的访问。普通的Java正则表达式库只支持两个标准的Unicode属性。不过,在JDK7中,将支持Unicode脚本属性,它几乎比Block属性更可取。因此,您可以在JDK7中编写
\p{Script=Latin}
\p{SC=Latin}
,或捷径
\p{Latin}
,从拉丁脚本中获取任何字符。这导致了非常普遍需要的
[\p{Latin}\p{Common}\p{Inherited}]

请注意,这不会从所有字符中删除您可能认为的“重音”标记!它不会为许多人这样做。例如,您不能通过这种方式将Đ转换为Dø转换为o。为此,您需要将代码点减少到与Unicode排序规则表中相同的主排序规则强度相匹配的代码点

另一个
\p{Mn}
失败的地方当然是包含像
\p{Me}
这样的标记,但是也有
\p{Diacritic}
字符不是标记。遗憾的是,您需要完全的属性支持,这意味着JNI对ICU或Perl都是如此。恐怕Java在Unicode支持方面有很多问题

哦,等等,我看你是葡萄牙人。如果您只处理葡萄牙语文本,那么应该没有任何问题


然而,我敢打赌,你并不是真的想消除口音,而是想能够“无意识地”匹配事物,对吗?如果是,则可以使用。如果在主要强度下进行比较,则重音标记不起作用。我一直这样做,因为我经常处理西班牙语文本。如果你需要的话,我举了一个例子,告诉你如何为坐在这里的某个地方的西班牙人做到这一点。

花了我一段时间,但我把它们都找出来了:

这应该包括所有zalgo字符,包括在“正常”范围内绕过的字符

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F\u0483-\u0486\u05C7\u0610-\u061A\u0656-\u065F\u0670\u06D6-\u06ED\u0711\u0730-\u073F\u0743-\u074A\u0F18-\u0F19\u0F35\u0F37\u0F72-\u0F73\u0F7A-\u0F81\u0F84\u0e00-\u0eff\uFC5E-\uFC62])

希望这能为您节省一些时间。

因此,我必须假设在整个web(甚至在这里是So)中给出的方法不是推荐的“删除”单词的方法。我只为葡萄牙语做了一个直截了当的测试,但看到了这种奇怪的方法(就像你说的,它适合我的目的,但我的上一个方法确实如此!)。那么,是否有一种更好的“实施良好”的方法可以覆盖大多数场景?举个例子就好了。谢谢您的时间。@Marclopes:我一直保持数据完整,并使用Unicode排序算法进行主要强度比较。这样,它只比较字母,而忽略大小写和重音符号。它还让应该是同一个字母的东西变成了同一个字母,去除重音只是一种苍白和令人不满意的近似。另外,如果你能以一种你想要的但不需要的方式处理数据,那么不破坏数据就更干净了。回答得不错,不过有一个问题,我能在java中使用Normalizer并使用incombindingDiacriticalMarks,但排除一些字符,如u,以避免转换为u吗?是的,我完全理解这一切。很显然,unicode中的“组合标记”比变音符号多,这只是一个注释。