从字符串中提取所有表情符号的正则表达式是什么?

vis*_*ksh 43 java regex utf-8 emoji

我有一个用UTF-8编码的字符串.例如:

Thats a nice joke  
Run Code Online (Sandbox Code Playgroud)

我必须提取句子中的所有表情符号.表情符号可以是任何表情符号

当在终端使用命令查看此句子时,less text.txt它被视为:

Thats a nice joke <U+1F606><U+1F606><U+1F606> <U+1F61B>
Run Code Online (Sandbox Code Playgroud)

这是表情符号的相应UTF代码.emojis的所有代码都可以在emojitracker找到.

为了找到所有的出现,我使用了正则表达式模式,(<U\+\w+?>)但它不适用于UTF-8编码的字符串.

以下是我的代码:

    String s="Thats a nice joke  ";
    Pattern pattern = Pattern.compile("(<U\\+\\w+?>)");
    Matcher matcher = pattern.matcher(s);
    List<String> matchList = new ArrayList<String>();

    while (matcher.find()) {
        matchList.add(matcher.group());
    }

    for(int i=0;i<matchList.size();i++){
        System.out.println(matchList.get(i));

    }
Run Code Online (Sandbox Code Playgroud)

这个pdfRange: 1F300–1F5FF for Miscellaneous Symbols and Pictographs.所以我想捕捉这个范围内的任何角色.

gid*_*dim 45

使用emoji-java我写了一个简单的方法,删除所有表情符号,包括fitzpatrick修饰符.需要一个外部库,但比那些怪物正则表达式更容易维护.

使用:

String input = "A string with a \uD83D\uDC66\uD83C\uDFFFfew emojis!";
String result = EmojiParser.removeAllEmojis(input);
Run Code Online (Sandbox Code Playgroud)

emoji-java maven安装:

<dependency>
  <groupId>com.vdurmont</groupId>
  <artifactId>emoji-java</artifactId>
  <version>3.1.3</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

gradle这个:

compile 'com.vdurmont:emoji-java:3.1.3'
Run Code Online (Sandbox Code Playgroud)

编辑:以前提交的答案被拉入emoji-java源代码.

  • 我喜欢这样的答案.这就像一个魅力.谢谢! (3认同)

T.J*_*der 29

你刚才提到的pdf范围:1F300-1F5FF用于其他符号和象形文字.所以我想说要捕捉这个范围内的任何角色.现在该怎么办?

好的,但我会注意到你问题中的表情符号超出了这个范围!:-)

事实上,这些0xFFFF事情使事情变得复杂,因为Java字符串存储了UTF-16.所以我们不能只使用一个简单的字符类.我们将有代理对.(更多:http://www.unicode.org/faq/utf_bom.html)

UTF-16中的U + 1F300最终成为该对\uD83C\uDF00; U + 1F5FF结束了\uD83D\uDDFF.请注意,第一个字符上升,我们至少跨越一个边界.因此,我们必须知道我们正在寻找的代理对的范围.

我没有沉浸在关于UTF-16内部运作的知识中,我写了一个程序来查明(最后的来源 - 如果我是你,我会仔细检查它,而不是相信我).它告诉我,我们正在寻找\uD83C范围内的任何内容\uDF00-\uDFFF(包括),或者\uD83D后面是范围内的任何内容\uDC00-\uDDFF(包括).

所以掌握了这些知识,理论上我们现在可以编写一个模式:

// This is wrong, keep reading
Pattern p = Pattern.compile("(?:\uD83C[\uDF00-\uDFFF])|(?:\uD83D[\uDC00-\uDDFF])");
Run Code Online (Sandbox Code Playgroud)

这是两个非捕获组的交替,第一组以对开始\uD83C,第二组以对开始\uD83D.

但那失败了(找不到任何东西).我很确定这是因为我们试图在不同的地方指定代理对的一半:

Pattern p = Pattern.compile("(?:\uD83C[\uDF00-\uDFFF])|(?:\uD83D[\uDC00-\uDDFF])");
// Half of a pair --------------^------^------^-----------^------^------^
Run Code Online (Sandbox Code Playgroud)

我们不能像这样拆分代理对,因为某种原因,它们被称为代理.:-)

因此,我认为我们根本不能使用正则表达式(或者实际上,任何基于字符串的方法).我想我们必须搜索char数组.

char数组包含UTF-16值,因此如果我们以困难的方式查找数据,我们可以在数据中找到这些半对:

String s = new StringBuilder()
                .append("Thats a nice joke ")
                .appendCodePoint(0x1F606)
                .appendCodePoint(0x1F606)
                .appendCodePoint(0x1F606)
                .append(" ")
                .appendCodePoint(0x1F61B)
                .toString();
char[] chars = s.toCharArray();
int index;
char ch1;
char ch2;

index = 0;
while (index < chars.length - 1) { // -1 because we're looking for two-char-long things
    ch1 = chars[index];
    if ((int)ch1 == 0xD83C) {
        ch2 = chars[index+1];
        if ((int)ch2 >= 0xDF00 && (int)ch2 <= 0xDFFF) {
            System.out.println("Found emoji at index " + index);
            index += 2;
            continue;
        }
    }
    else if ((int)ch1 == 0xD83D) {
        ch2 = chars[index+1];
        if ((int)ch2 >= 0xDC00 && (int)ch2 <= 0xDDFF) {
            System.out.println("Found emoji at index " + index);
            index += 2;
            continue;
        }
    }
    ++index;
}
Run Code Online (Sandbox Code Playgroud)

显然这只是调试级代码,但它确实起到了作用.(在你的给定字符串中,使用它的表情符号,当然它不会找到任何东西,因为它们超出了范围.但是如果你改变第二对的上限0xDEFF而不是0xDDFF,那就会.它不知道是否也会但不包括非表情符号.)


我的计划的来源,以找出代理范围是什么:

public class FindRanges {

    public static void main(String[] args) {
        char last0 = '\0';
        char last1 = '\0';
        for (int x = 0x1F300; x <= 0x1F5FF; ++x) {
            char[] chars = new StringBuilder().appendCodePoint(x).toString().toCharArray();
            if (chars[0] != last0) {
                if (last0 != '\0') {
                    System.out.println("-\\u" + Integer.toHexString((int)last1).toUpperCase());
                }
                System.out.print("\\u" + Integer.toHexString((int)chars[0]).toUpperCase() + " \\u" + Integer.toHexString((int)chars[1]).toUpperCase());
                last0 = chars[0];
            }
            last1 = chars[1];
        }
        if (last0 != '\0') {
            System.out.println("-\\u" + Integer.toHexString((int)last1).toUpperCase());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

\uD83C \uDF00-\uDFFF
\uD83D \uDC00-\uDDFF


Kar*_*har 17

有类似的问题.以下为我提供了良好的服务,并与代理人配对

public class SplitByUnicode {
    public static void main(String[] argv) throws Exception {
        String string = "Thats a nice joke  ";
        System.out.println("Original String:"+string);
        String regexPattern = "[\uD83C-\uDBFF\uDC00-\uDFFF]+";
        byte[] utf8 = string.getBytes("UTF-8");

        String string1 = new String(utf8, "UTF-8");

        Pattern pattern = Pattern.compile(regexPattern);
        Matcher matcher = pattern.matcher(string1);
        List<String> matchList = new ArrayList<String>();

        while (matcher.find()) {
            matchList.add(matcher.group());
        }

        for(int i=0;i<matchList.size();i++){
            System.out.println(i+":"+matchList.get(i));

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:


Original String:Thats a nice joke  
0:
1:

/sf/answers/1685011961/找到正则表达式


小智 10

这在java 8中对我有用:

public static String mysqlSafe(String input) {
  if (input == null) return null;
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < input.length(); i++) {
      if (i < (input.length() - 1)) { // Emojis are two characters long in java, e.g. a rocket emoji is "\uD83D\uDE80";
        if (Character.isSurrogatePair(input.charAt(i), input.charAt(i + 1))) {
          i += 1; //also skip the second character of the emoji
          continue;
        }
      }
      sb.append(input.charAt(i));
    }

  return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)


Shi*_*ang 6

你可以这样做

    String s="Thats a nice joke  ";
    Pattern pattern = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
                                      Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
    Matcher matcher = pattern.matcher(s);
    List<String> matchList = new ArrayList<String>();

    while (matcher.find()) {
        matchList.add(matcher.group());
    }

    for(int i=0;i<matchList.size();i++){
        System.out.println(matchList.get(i));
    }
Run Code Online (Sandbox Code Playgroud)


小智 6

提取所有表情符号的最佳正则表达式是:

(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])
Run Code Online (Sandbox Code Playgroud)

它可以识别许多其他答案未说明的单字符表情符号。有关此正则表达式如何工作的更多信息,请查看这篇文章。https://medium.com/@thekevinscott/emojis-in-javascript-f693d0eb79fb#.enomgcu63


Ven*_*ang 6

有两种方法可以解决这个棘手的问题。

第一个是使用第三方库,例如emoji-java和 emoji4j。这些都是上面提到的。您可以轻松地使用方法containsEmojiremovesEmoji等。并且在您自己的应用程序中,您需要不断更新这些库。

对于我来说,我想找到一个简单的解决方案来解决这个问题。

经过一整天的搜索,我发现了一个神奇的正则表达式:

"(?:[\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?)"

我在Java中测试过OK。它完美地解决了我的问题。

您可以在 Github 页面上查看:

https://github.com/zly394/EmojiRegex

笔记:

@Eric Nakakawa 提供的答案包含一些错误,无法正常操作。


小智 5

假设您要求标准的Unicode表情符号范围(供应商提供不同的块),您可以考虑以下三个范围:

  • 0x20a0 - 0x32ff
  • 0x1f000 - 0x1ffff
  • 0xfe4e5 - 0xfe4ee

除了TJCrowder与我们分享的所有深思熟虑的解释外,需要说的是从Java 7开始可以轻松匹配UTF-16编码的代理对.

看看文档:

http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html

Unicode字符也可以通过使用其十六进制表示法(十六进制代码点值)直接表示为正则表达式,如construct\x {...}中所述,例如,补充字符U + 2011F可以指定为\ x {2011F},而不是代理对\ uD840\uDD1F的两个连续Unicode转义序列.

然而,如果你不能切换到Java 7,你可以扩展Guava提供的有价值的UnicodeEscaper.

这里是为了示例的实现:

public class SimpleEscaper extends UnicodeEscaper
{
    @Override
    protected char[] escape(int codePoint)
    {
        if (0x1f000 >= codePoint && codePoint <= 0x1ffff)
        {
            return Integer.toHexString(codePoint).toCharArray();
        }

        return Character.toChars(codePoint);
    }
}
Run Code Online (Sandbox Code Playgroud)


Ser*_*yan 5

表情符号正则表达式

public static final String sEmojiRegex = "(?:[\\u2700-\\u27bf]|" +

        "(?:[\\ud83c\\udde6-\\ud83c\\uddff]){2}|" +
        "[\\ud800\\udc00-\\uDBFF\\uDFFF]|[\\u2600-\\u26FF])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe23\\u20d0-\\u20f0]|[\\ud83c\\udffb-\\ud83c\\udfff])?" +

        "(?:\\u200d(?:[^\\ud800-\\udfff]|" +

        "(?:[\\ud83c\\udde6-\\ud83c\\uddff]){2}|" +
        "[\\ud800\\udc00-\\uDBFF\\uDFFF]|[\\u2600-\\u26FF])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe23\\u20d0-\\u20f0]|[\\ud83c\\udffb-\\ud83c\\udfff])?)*|" +

        "[\\u0023-\\u0039]\\ufe0f?\\u20e3|\\u3299|\\u3297|\\u303d|\\u3030|\\u24c2|[\\ud83c\\udd70-\\ud83c\\udd71]|[\\ud83c\\udd7e-\\ud83c\\udd7f]|\\ud83c\\udd8e|[\\ud83c\\udd91-\\ud83c\\udd9a]|[\\ud83c\\udde6-\\ud83c\\uddff]|[\\ud83c\\ude01-\\ud83c\\ude02]|\\ud83c\\ude1a|\\ud83c\\ude2f|[\\ud83c\\ude32-\\ud83c\\ude3a]|[\\ud83c\\ude50-\\ud83c\\ude51]|\\u203c|\\u2049|[\\u25aa-\\u25ab]|\\u25b6|\\u25c0|[\\u25fb-\\u25fe]|\\u00a9|\\u00ae|\\u2122|\\u2139|\\ud83c\\udc04|[\\u2600-\\u26FF]|\\u2b05|\\u2b06|\\u2b07|\\u2b1b|\\u2b1c|\\u2b50|\\u2b55|\\u231a|\\u231b|\\u2328|\\u23cf|[\\u23e9-\\u23f3]|[\\u23f8-\\u23fa]|\\ud83c\\udccf|\\u2934|\\u2935|[\\u2190-\\u21ff]";
Run Code Online (Sandbox Code Playgroud)

一些表情符号 (1627)

// count = 1627
public static final String sEmojiTest = "?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0??1??2??3??4??5??6??7??8??9??#??*?????????????????????????????????????????????????™?©?®????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
Run Code Online (Sandbox Code Playgroud)

测试表情符号的功能

public void checkMatchingEmojis() {

    final Pattern pattern = Pattern.compile(sEmojiRegex);
    final Matcher matcher = pattern.matcher(sEmojiTest);
    int foundEmojiCount = 0;
    while (matcher.find()) {
        System.out.println("Full match: " + matcher.group(0));
        foundEmojiCount++;
    }
    System.out.println("*******************************************");
    System.out.println("Input Emoji count = 1627");
    System.out.println("Captured Emoji count = " + foundEmojiCount);
    System.out.println("*******************************************");

}
Run Code Online (Sandbox Code Playgroud)

是在所有 unicode 10 表情符号上测试的要点

感谢Kevin Scott写了一个很好的例子