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

Rih*_*rds 4 java regex unicode character-properties

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

到目前为止我发现的是:\p{L}\p{M}但是我不确定如何在regexp中启动它,所以它会像我上面解释的那样工作.这会是一个正则表达式否定的情况吗?

Paŭ*_*ann 8

是的,你需要否定.正则表达式将[^\p{L}]用于除字母之外任何内容.写这个的另一种方法是\P{L}.

\p{M}意思是"所有标记",因此[^\p{L}\p{M}]意味着**任何既不是字母也不标记的东西.这也可以写成[\P{L}&&[\P{M}]],但这并不是更好.

在Java-String中,所有\都必须加倍,所以你可以string.replaceAll("[^\\p{L}\\p{M}]", "replacement")在那里写.


来自评论:

顺便说一下,关于你的回答,什么属于商标类别?我甚至需要吗?不仅仅是字母对名字没问题吗?

此类别包含子类别

  • Mn:标记,非间距

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

  • 麦克:马克,间距组合.

    这些很少......我发现它们主要是南亚文字和音符.例如,我们有U + 1D165,MUSICAL SYMBOL COMBINING STEM.텦,可以与U + 1D15D,MUSICAL SYMBOL WHOLE NOTE,combined组合,类似于텝텦.(嗯,这些图像看起来不对.我想我的浏览器不支持这些字符.看看代码图表,如果它们在这里错了.)

  • 我:马克,附上

    这些标记以某种方式包含基本字母(前一个,如果我理解的话).一个例子是U + 20DD,⃝,它允许创建类似的东西A?.(如果我理解的话,这应该被呈现为圆圈所包围的A.在我的浏览器中它不会.)另一个是U + 20E3,⃣,COMBINING ENCLOSING KEYCAP,它应该给出一个关键帽的外观随信(A⃣).(它们不会显示在我的浏览器中.如果您看不到它们,请查看代码表.)

您可以通过所有搜索中找到他们Unicode的DATA.TXT;Mn;,;Mc;;Me;分别.常见问题解答中包含更多信息:字符和组合标记.

你需要它们吗?我不确定.我认为,最常见的名字(至少在拉丁字母表中)会使用预先组合的字母.但是用户可能会以分解的形式输入它们 - 我认为在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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是输出(在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 | ?         | ?        | ? | -   | -   | ?   | ?   
Run Code Online (Sandbox Code Playgroud)

我们可以看到:

  1. [^\pL\pM]不是等同于[\PL\PM]
  2. [\PL\PM] 真的匹配一切,但是
  3. 仍然[\PL\PM]不等于.,因为.不匹配\n\r.

第二点是由以下事实引起的[\PL\PM]联合\PL\PM:\PL含有比L(包括M)之外的所有类别的字符,并\PM含有来自除M(包括L)以外的所有类别的字符-它们一起包含整个字符集.

[^pL\pM],在另一方面,是的并集的补集\pL\pM,这等同于交叉点\PLPM.