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

时间:2018-05-01 10:54:48

标签: java unicode emoji java-6

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

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标准。

2 个答案:

答案 0 :(得分: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}应该有用。

答案 1 :(得分:1)

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

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,后者全部删除。