Regex:什么是 InCombiningDiacriticalMarks?

2022-08-31 10:53:24

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

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

我用这个方法替换了我的“手工制作”方法,但我需要了解替换All的“正则表达式”部分

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

谢谢。


答案 1

\p{InCombiningDiacriticalMarks}是一个 Unicode 块属性。在JDK7中,您将能够使用 两部分符号编写它 ,这对读者来说可能更清晰。它记录在UAX#44中:“Unicode字符数据库”。\p{Block=CombiningDiacriticalMarks}

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

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

块几乎从来都不是你想要的。

在这种情况下,我怀疑您可能希望使用 该属性 ,又名 。Combining_Diacriticals块中的所有代码点都是这种类型的。还有(截至 Unicode 6.0.0)1087 个Nonspacing_Marks不在该块中。\p{Mn}\p{Nonspacing_Mark}

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

你必须使用JNI来访问ICU C++正则表达式库,就像Google所做的那样,以便访问类似的东西,因为现在只有ICU和Perl可以访问所有Unicode属性。普通的 Java 正则表达式库仅支持几个标准的 Unicode 属性。在 JDK7 中,虽然支持 Unicode 脚本属性,但它比 Block 属性更可取。因此,你可以在JDK7中写或,或者简称,从拉丁字母中获取任何字符。这导致了非常普遍的需求。\p{BC=NSM}\p{Script=Latin}\p{SC=Latin}\p{Latin}[\p{Latin}\p{Common}\p{Inherited}]

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

另一个失败的地方当然是封闭标记,显然,但也有一些字符不是标记。可悲的是,您需要完整的财产支持,这意味着JNI可以用于ICU或Perl。恐怕Java在Unicode支持方面存在很多问题。\p{Mn}\p{Me}\p{Diacritic}

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

但是,我敢打赌,您并不是真的想删除重音,而是希望能够“不区分口音”地匹配事物,对吗?如果是这样,则可以使用 ICU4J(Java 的 ICU)归类执行此操作。如果您在主要强度上进行比较,则重音符号将不计算在内。我一直这样做是因为我经常处理西班牙语文本。我有一个例子,如果你需要的话,如何为西班牙人坐在这里的某个地方做这件事。


答案 2

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

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

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