【问题标题】:Java regex matches diacritics for the Latin corresponding charactersJava regex 匹配拉丁对应字符的变音符号
【发布时间】:2017-07-02 00:19:48
【问题描述】:

我正在尝试使用诸如[ăâîșțĂÂÎȘȚ] 之类的正则表达式来匹配罗马尼亚字母变音符号(ISO 8859-16/Windows-1250)。问题是正则表达式也会匹配 a,i,s,t,A,I,S,T(上述变音符号的拉丁字母对应字符)的正则表达式,我不想要这个。 由于性能时间问题,我没有尝试逐个字符地比较字符串。

无论如何我可以使正则表达式完全匹配这些字符吗?

【问题讨论】:

  • 您使用什么正则表达式引擎/语言?这不应该发生,请参阅here
  • does not seem true。您能否提供一个 Java 演示来显示您描述的行为?

标签: java regex nlp diacritics


【解决方案1】:

如果您的正则表达式作为文字呈现的文本存在,则它已经被合并
并且应该作为不同的代码点存在。

000074    t    LATIN SMALL LETTER T
+
000326    ̦    COMBINING COMMA BELOW
=
00021B    ț    LATIN SMALL LETTER T WITH COMMA BELOW

以防万一,您应该使用十六进制代码点来表示它们,即。 u\021B

Java 引擎是否有可能从正则表达式中剥离组合字符?
x21B 在哪里变成 x74?可能就是这样。

同时,如果您希望源中的字母不会被渲染,您可以
使用像\p{Script=Latin}\p{Block=Combining_Diacritical_Marks}这样的正则表达式
得到那些。

更新信息:
在寻找事实上的解决方案时,我遇到了这个 Java 信息​​
来自http://www.regular-expressions.info/unicode.html

在 Java 中,正则表达式标记 \uFFFF 仅匹配指定的 代码点,即使您打开规范等价。 但是,同样的语法 \uFFFF 也用于插入 Unicode 字符转换为 Java 源代码中的文字字符串 代码。 Pattern.compile("\u00E0") 将匹配 à的单码点和双码点编码, 而 Pattern.compile("\u00E0") 只匹配 单码点版本。请记住,在编写 正则表达式作为 Java 字符串文字,必须转义反斜杠。 前一个 Java 代码编译正则表达式 à,而后者 编译\u00E0。取决于你在做什么, 差异可能很大。

因此,通过在类中输入对偶文字,它看起来像 Pattern.compile("[à]")
实际上会匹配

000061    a    LATIN SMALL LETTER A
or
000300    ̀    COMBINING GRAVE ACCENT
or
0000E0    à    LATIN SMALL LETTER A WITH GRAVE  

将代理对放在类中时,这会产生同样的问题。
有一个解决方案。

避免在类中输入这些文字。
相反,将它们作为一系列交替
(?:à|_|_|_)

这样做会强制它匹配任何一个

000061    a    LATIN SMALL LETTER A
000300    ̀    COMBINING GRAVE ACCENT

0000E0    à    LATIN SMALL LETTER A WITH GRAVE  

它不会像您现在看到的那样独立于 grave 匹配 a

注意 - 如果你只使用“[\\u00E0]”,你会错过a + grave
这是有效的。

【讨论】:

【解决方案2】:

我相信这是因为这些字符被视为两个 Unicode 代码点。我建议尝试使用像 \uFFFF 这样的语法来专门匹配代码点,其中 FFFF 是代码点。确切的语法将取决于您使用的正则表达式实现。

请记住,Unicode 字符可以编码为单个代码点或多个代码点,因此您需要考虑这一点。示例:à 编码为 U+0061 U+0300 和 U+00E0。

我希望这会有所帮助!

【讨论】:

    【解决方案3】:

    正如 Unicode 中已经提到的,有两种选择。

    '\u0061'    'a'   LATIN SMALL LETTER A
    '\u0300'     ̀     COMBINING GRAVE ACCENT
    

    '\u00E0'    'à'   LATIN SMALL LETTER A WITH GRAVE  
    

    有一个Normalizer 可以“规范化”为任一形式(并处理连字):

    String regex = "(?u)[ăâîșțĂÂÎȘȚ]";
    regex = Normalizer.normalize(regex, Form.NFC); // Composed form
    Pattern pattern = Pattern.compile(regex);
    

    使用 "(?u)" 或带有 UNICODE 标志的 Pattern.compile 标志可能已经解决了问题。但是使用没有单独的拉丁文 ('a') 的 Unicode 变体当然可以。

    规范化器应该特别应用于搜索到的字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-10
      • 2011-03-14
      • 1970-01-01
      • 1970-01-01
      • 2013-06-27
      • 1970-01-01
      相关资源
      最近更新 更多