为什么这个表情符号正则表达式也匹配数字

why is this emoji regex also matching numerics

我正在编写一个需要从字符串中去除表情符号的程序,发现这个正则表达式似乎删除了我迄今为止测试过的所有表情符号:

private static final String EMOJI_REGEX= "[\u200D(?:"
  + "[\uD83C\uDF00-\uD83D\uDDFF]|"
  + "[\uD83E\uDD00-\uD83E\uDDFF]|"
  + "[\uD83D\uDE00-\uD83D\uDE4F]|"
  + "[\uD83D\uDE80-\uD83D\uDEFF]|"
  + "[\u2600-\u26FF]\uFE0F?|"
  + "[\u2700-\u27BF]\uFE0F?|"
  + "\u24C2\uFE0F?|"
  + "[\uD83C\uDDE6-\uD83C\uDDFF]{1,2}|"
  + "[\uD83C\uDD70\uD83C\uDD71\uD83C\uDD7E\uD83C\uDD7F\uD83C\uDD8E\uD83C\uDD91-\uD83C\uDD9A]\uFE0F?|"
  + "[\u0023\u002A\u0030-\u0039]\uFE0F?\u20E3|[\u2194-\u2199\u21A9-\u21AA]\uFE0F?|"
  + "[\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55]\uFE0F?|"
  + "[\u2934\u2935]\uFE0F?|"
  + "[\u3030\u303D]\uFE0F?|"
  + "[\u3297\u3299]\uFE0F?|"
  + "[\uD83C\uDE01\uD83C\uDE02\uD83C\uDE1A\uD83C\uDE2F\uD83C\uDE32-"
  + "\uD83C\uDE3A\uD83C\uDE50\uD83C\uDE51]\uFE0F?|"
  + "[\u203C\u2049]\uFE0F?|[\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE]\uFE0F?|[\u00A9\u00AE]\uFE0F?|"
  + "[\u2122\u2139]\uFE0F?|\uD83C\uDC04\uFE0F?|\uD83C\uDCCF\uFE0F?|"
  + "[\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA]\uFE0F?)]";

当我像这样使用这个正则表达式时:

strippedString = regexString.replaceAll(EMOJI_REGEX, "");

它成功删除了所有表情符号。但是,我尝试使用我不想剥离的数据对其进行测试,并且该正则表达式似乎也与数字匹配。例如,当我通过测试字符串 Testing £1.01☂ 时,输出为 Testing £..

我尝试从上面的正则表达式中删除 \u0030-\u0039 范围,但现在我得到 Testing £.0.

谁能告诉我这是怎么回事,我该如何解决这个问题?

重要说明 由于古老的体系结构,此问题的解决方案必须符合 java 6。

由于您的正则表达式只是一堆 | 的范围,我们可以编写一些测试代码来查看哪些范围删除了数字:

public class RegexTest
{
    private static final String regexbegin = "[\u200D(?:";
    private static final String regexend = ")]";
    private static final String[] regexparts =
    {
        "[\uD83C\uDF00-\uD83D\uDDFF]",
        "[\uD83E\uDD00-\uD83E\uDDFF]",
        "[\uD83D\uDE00-\uD83D\uDE4F]",
        "[\uD83D\uDE80-\uD83D\uDEFF]",
        "[\u2600-\u26FF]\uFE0F?",
        "[\u2700-\u27BF]\uFE0F?",
        "\u24C2\uFE0F?",
        "[\uD83C\uDDE6-\uD83C\uDDFF]{1,2}",
        "[\uD83C\uDD70\uD83C\uDD71\uD83C\uDD7E\uD83C\uDD7F\uD83C\uDD8E\uD83C\uDD91-\uD83C\uDD9A]\uFE0F?",
        "[\u0023\u002A\u0030-\u0039]\uFE0F?\u20E3",
        "[\u2194-\u2199\u21A9-\u21AA]\uFE0F?",
        "[\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55]\uFE0F?",
        "[\u2934\u2935]\uFE0F?",
        "[\u3030\u303D]\uFE0F?",
        "[\u3297\u3299]\uFE0F?",
        "[\uD83C\uDE01\uD83C\uDE02\uD83C\uDE1A\uD83C\uDE2F\uD83C\uDE32-\uD83C\uDE3A\uD83C\uDE50\uD83C\uDE51]\uFE0F?",
        "[\u203C\u2049]\uFE0F?",
        "[\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE]\uFE0F?",
        "[\u00A9\u00AE]\uFE0F?",
        "[\u2122\u2139]\uFE0F?",
        "\uD83C\uDC04\uFE0F?",
        "\uD83C\uDCCF\uFE0F?",
        "[\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA]\uFE0F?",
    };

    public static void main(final String[] args)
    {
        final String test = "Testing  £1.01☂";
        for (int i = 0; i < regexparts.length; i++) {
            final String regex = regexbegin + regexparts[i] + regexend;
            System.out.println(i + ": " + test.replaceAll(regex, ""));
        }
    }
}

使用这段代码我们得到:

0: Testing  £1.01☂
1: Testing  £1.01☂
2: Testing  £1.01☂
3: Testing  £1.01☂
4: Testing  £1.01
5: Testing  £1.01☂
6: Testing  £1.01☂
7: Testing  £.0☂
8: Testing  £1.01☂
9: Testing  £.☂
10: Testing  £1.01☂
11: Testing  £1.01☂
12: Testing  £1.01☂
13: Testing  £1.01☂
14: Testing  £1.01☂
15: Testing  £1.01☂
16: Testing  £1.01☂
17: Testing  £1.01☂
18: Testing  £1.01☂
19: Testing  £1.01☂
20: Testing  £1.01☂
21: Testing  £1.01☂
22: Testing  £1.01☂

所以索引 7 和索引 9 处的范围是你的罪魁祸首:

"[\uD83C\uDDE6-\uD83C\uDDFF]{1,2}"

"[\u0023\u002A\u0030-\u0039]\uFE0F?\u20E3"

直接在数字上使用这些仅测试 String

System.out.println("7: " + "0123456789".replaceAll(regexbegin + regexparts[7] + regexend, ""));
System.out.println("9: " + "0123456789".replaceAll(regexbegin + regexparts[9] + regexend, ""));

产生这个:

7: 03456789
9: 

前者去掉1和2,后者去掉所有数字

Max Vollmer 已经回答,但想知道为什么

[\u0023\u002A\u0030-\u0039]\uFE0F?\u20E3

匹配号码,见Emoji Keyboard/Display Test Data

如您所见,[\u0030-\u0039]\uFE0F?\u20E3 匹配键帽范围 0 到 9(请参阅子组:键帽)。

至于

[\uD83C\uDDE6-\uD83C\uDDFF]{1,2}

删除范围 {1,2} 应该有效。