正则表达式:什么是InCombiningDiacriticalMarks?


86

以下代码是众所周知的将重音符转换为纯文本的代码:

Normalizer.normalize(text, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");

我用这种方法代替了“手工制作”方法,但是我需要了解replaceAll的“ regex”部分

1)什么是“ InCombiningDiacriticalMarks”?
2)它的文档在哪里?(和类似的?)

谢谢。


另请参见stackoverflow.com/a/29111105/32453显然,在unicode中,不仅有变音符号,而且还有更多的“组合符号”。
rogerdpack 2015年

Answers:


74

\p{InCombiningDiacriticalMarks}是Unicode块属性。在JDK7中,您将可以使用两部分表示法来编写它\p{Block=CombiningDiacriticalMarks},这对于读者来说可能更清楚。它在UAX#44中进行了记录:“ Unicode字符数据库”

这意味着代码点落在一个特定的范围内,即一个块,该块已通过该名称分配给事物使用。这是一种不好的方法,因为不能保证该范围内的代码点是或不是任何特定事物,也不保证该块之外的代码点本质上不是同一字符。

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

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

在这种情况下,我怀疑您可能想使用\p{Mn}aka属性\p{Nonspacing_Mark}。Combining_Diacriticals块中的所有代码点均属于此类。从Unicode 6.0.0开始,还有1087个Nonspacing_Marks不是该块中。

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

您必须像Google一样使用JNI来获取ICU C ++ regex库,以便访问像之类的东西\p{BC=NSM},因为现在只有ICU和Perl允许访问所有Unicode属性。普通的Java regex库仅支持几个标准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支持方面存在很多问题。

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

但是,我敢打赌,您并不是真的想删除重音符号,而是希望能够“不区分重音符号”来匹配内容,对吗?如果是这样,则可以使用ICU4J(Java的ICU)整理程序类进行操作。如果您以主要强度进行比较,则重音符号将不会计入。我一直这样做,因为我经常处理西班牙语文本。我有一个示例,说明如何在需要时坐在这里的西班牙人。


因此,我必须假设,整个网络(甚至在此处还是这样)给出的方法都不是“ DeAccent”一词的推荐方法。我直接为葡萄牙语制作了一个方法,但是看到了这种奇怪的方法(就像您说的那样,它可以达到我的目的,但是我的最后一个方法就可以了!)。因此,是否有一种更好的“实施良好”的方法可以覆盖大多数情况?一个例子将是非常好的。谢谢你的时间。
marcolopes 2011年

1
@Marcolopes:我一直保持数据不变,并使用Unicode排序算法进行主强度比较。这样,它仅比较字母,而忽略大小写和重音符号。它还使应该是相同字母的事物成为相同字母,而去除重音符号只是苍白且不令人满意的近似值。另外,如果您可以按照自己想要的方式使用数据,而又不需要这样做,则可以更轻松地处理数据。
tchrist 2011年

很好的答案,但是一个问题,我可以在Java中使用Normalizer并使用InCombiningDiacriticalMarks,但不能将诸如ü之类的某些字符转换为u吗?
AlexCon 2014年

6
是啊,我完全明白了这一切
多纳尔

4

花了我一段时间,但我把它们全部捞出了:

这里的正则表达式应包括所有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])

希望这可以节省您一些时间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.