java - 如何在 Java 中正确编写 unicode 名字的正则表达式?

标签 java regex unicode character-properties

我需要编写一个正则表达式,以便在进一步发送之前替换用户输入中的无效字符。我想我需要使用 string.replaceAll("regex", "replacement") 来做到这一点。 特定的代码行应该替换所有不是 unicode 字母的字符。所以它是一个 unicode 字符的白名单。基本上它是验证和替换用户名字的无效字符。

到目前为止我发现的是:\p{L}\p{M},但我不确定如何在正则表达式中启动它,这样它才能像我一样工作上面解释了。这会是正则表达式否定案例吗?

最佳答案

是的,你需要否定。正则表达式将是 [^\p{L}] 表示除字母以外的任何内容。另一种写法是 \P{L}

\p{M} 表示“所有标记”,因此 [^\p{L}\p{M}] 表示**任何既不是字母的东西也没有标记。这也可以写成 [\P{L}&&[\P{M}]],但这并不是真的更好。

在 Java 字符串中,所有 \ 都必须加倍,因此您可以编写 string.replaceAll("[^\\p{L}\\p{M}]", "替换") 那里。


来自评论:

By the way, regarding to your answer, what fall in the marks category? Do I even need that? Wouldn't just letters be fine for firstname?

这个类别由子类别组成

  • Mn:标记,非间距

    一个例子是 ̀, U+0300。这是 COMBINING GRAVE ACCENT,可以与字母(前面的字母)一起使用来创建重音字符。对于常用的重音字符,已经有一个预组合形式(例如 é),但对于其他的则没有。

  • Mc:标记,间距组合。

    这些很少见……我主要在南亚文字和音符中发现它们。例如,我们有 U+1D165,MUSICAL SYMBOL COMBINING STEM。 텦,可以与 U+1D15D,音乐符号全音符,텝 组合成 텝텦 之类的东西。 (嗯,图片在这里看起来不对。我想我的浏览器不支持这些字符。看看 code charts ,如果它们在这里是错误的。)

  • 我:马克,封闭

    这些标记以某种方式包含了基本字母(如果我理解正确的话,是前一个)。一个例子是 U+20DD,⃝,它允许创建像 A⃝ 这样的东西。 (如果我理解正确的话,这应该呈现为一个圆圈包围的 A。在我的浏览器中它没有。)另一个是 U+20E3,⃣,COMBINING ENCLOSING KEYCAP,它应该看起来像一个键帽上面有字母(A⃣)。 (它们没有在我的浏览器中显示。如果看不到它们,请查看 code chart。)

您可以通过搜索 Unicode-Data.txt 找到它们。分别为 ;Mn;;Mc;;Me;。更多信息在 FAQ: Characters and Combining Marks 中。 .

你需要它们吗?我在这里不确定。我认为,最常见的名字(至少在拉丁字母中)会使用预组合字母。但是用户可能会以分解的形式输入它们——我认为在 Mac OS X 上这实际上是默认的。在过滤掉未知字符之前,您必须运行规范化算法。 (如果您想比较名称而不仅仅是在屏幕上显示它们,无论如何运行规范化似乎是个好主意。)


编辑:与问题没有直接关系,但与评论中的讨论有关:

我写了一个快速测试程序来证明 [^\pL\pM] 不等同于 [\PL\PM]:

package de.fencing_game.paul.examples;

import java.util.regex.*;

public class RegexSample {

    static String[] regexps = {
        "[^\\pL\\pM]", "[\\PL\\PM]",
        ".", "\\pL", "\\pM",
        "\\PL", "\\PM"
    };

    static String[] strings = {
        "x", "A", "3", "\n", ".", "\t", "\r", "\f",
        " ", "-", "!", "»", "›", "‹", "«",
        "ͳ", "Θ", "Σ", "Ϫ", "Ж", "ؤ",
        "༬", "༺", "༼", "ང", "⃓", "✄",
        "⟪", "や", "゙", 
        "+", "→", "∑", "∢", "※", "⁉", "⧓", "⧻",
        "⑪", "⒄", "⒰", "ⓛ", "⓶",
        "\u0300" /* COMBINING GRAVE ACCENT, Mn */,
        "\u0BCD" /* TAMIL SIGN VIRAMA, Me */,
        "\u20DD" /* COMBINING ENCLOSING CIRCLE, Me */,
        "\u2166" /* ROMAN NUMERAL SEVEN, Nl */,
    };


    public static void main(String[] params) {
        Pattern[] patterns = new Pattern[regexps.length];

        System.out.print("       ");
        for(int i = 0; i < regexps.length; i++) {
            patterns[i] = Pattern.compile(regexps[i]);
            System.out.print("| " + patterns[i] + " ");
        }
        System.out.println();
        System.out.print("-------");
        for(int i = 0; i < regexps.length; i++) {
            System.out.print("|-" +
                             "--------------".substring(0,
                                                        regexps[i].length()) +
                             "-");
        }
        System.out.println();

        for(int j = 0; j < strings.length; j++) {
            System.out.printf("U+%04x ", (int)strings[j].charAt(0));
            for(int i = 0; i < regexps.length; i++) {
                boolean match = patterns[i].matcher(strings[j]).matches();
                System.out.print("| " + (match ? "✔" : "-")  +
                                 "         ".substring(0, regexps[i].length()));
            }
            System.out.println();
        }
    }
}

这是输出(在 OpenSUSE 上使用 OpenJDK 1.6.0_20):

       | [^\pL\pM] | [\PL\PM] | . | \pL | \pM | \PL | \PM 
-------|-----------|----------|---|-----|-----|-----|-----
U+0078 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+0041 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+0033 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+000a | ✔         | ✔        | - | -   | -   | ✔   | ✔   
U+002e | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0009 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+000d | ✔         | ✔        | - | -   | -   | ✔   | ✔   
U+000c | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0020 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+002d | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0021 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+00bb | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+203a | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2039 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+00ab | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0373 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0398 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+03a3 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+03ea | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+0416 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+0624 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+0f2c | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0f3a | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0f3c | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0f44 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+20d3 | -         | ✔        | ✔ | -   | ✔   | ✔   | -   
U+2704 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+27ea | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+3084 | -         | ✔        | ✔ | ✔   | -   | -   | ✔   
U+3099 | -         | ✔        | ✔ | -   | ✔   | ✔   | -   
U+002b | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2192 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2211 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2222 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+203b | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2049 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+29d3 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+29fb | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+246a | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+2484 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+24b0 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+24db | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+24f6 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   
U+0300 | -         | ✔        | ✔ | -   | ✔   | ✔   | -   
U+0bcd | -         | ✔        | ✔ | -   | ✔   | ✔   | -   
U+20dd | -         | ✔        | ✔ | -   | ✔   | ✔   | -   
U+2166 | ✔         | ✔        | ✔ | -   | -   | ✔   | ✔   

我们可以看到:

  1. [^\pL\pM] 等同于[\PL\PM]
  2. [\PL\PM] 确实匹配所有内容,但是
  3. 仍然 [\PL\PM] 不等于 .,因为 . 不匹配 \n\r

第二点是因为[\PL\PM]\PL\的union PM:\PL包含除L(包括M)以外的所有类别的字符,\PM包含除M(包括L)以外的所有类别的字符- 它们一起包含了整个角色轨道。

另一方面,

[^pL\pM]\pL\pM 并集的补集,它相当于 \PLPM交集

关于java - 如何在 Java 中正确编写 unicode 名字的正则表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6493954/

相关文章:

JavaBeans:如何拥有私有(private)数据?

python - 从一行中删除所有逗号字符,除非行以 # 使用 python regex 开头

regex - 正则表达式匹配以特殊字符结尾的句子,如 . ! ?但忽略像 George W. Bush,Mr. 这样的话。 ETC

unicode - 用于表示组合字符的 unicode 字形是什么?

java - 如何通过Java服务器跨两个网站发送消息

java - Netty 如何发送对象

java - 将符号链接(symbolic link)文件夹隐藏到硬链接(hard link)文件夹

javascript - 关于理解正则表达式的几个问题

python - IDNA nameprep 无效字符 u'\x94'

ruby-on-rails - 如何处理 UTF-8 电子邮件 header (如主题 :) using Ruby?