1. 概述

表情符号在我们的代码中处理的大量文本中经常出现,比如电子邮件或即时通讯服务中。本教程将介绍在Java应用程序中检测表情符号的多种方法。

2. Java如何表示表情符号?

每个表情符号都有一个唯一的Unicode值,它代表着这个符号。Java使用UTF-16对字符串中的Unicode字符进行编码。

UTF-16可以编码所有Unicode代码点。一个代码点可能由一个或两个代码单元组成。如果因为Unicode值超出了16位所能存储的范围,就需要使用一个代理对。代理对是由两个字符(或代码单元)组成的,它们组合起来表示一个单独的Unicode字符(或代码点)。有一个预留的代码单元范围用于代理对。

例如,Skull and Crossbones表情符号的Unicode值是“U+2620”,在字符串中存储为“\u2620️️”。我们只需要一个代码单元。然而,Bear Face表情符号的Unicode字符是“U+1F43B”,在字符串中会表示为“\uD83D\uDC3B”。这需要两个代码单元,因为Unicode值超过了单个单元的范围。

稍后我们将探讨这些内容,但这是基本概念的解释。

3. emoji-java

现成的解决方案是使用emoji-java库。要在项目中使用此库,我们需要将其导入到pom.xml中:

 <dependency>
     <groupId>com.vdurmont</groupId>
     <artifactId>emoji-java</artifactId>
    <version>5.1.1</version>
</dependency>

最新版本可以在Maven仓库中找到。

使用此库检查字母是否是表情符号非常简单。它在EmojiManager工具类中提供了静态方法isEmoji()

该方法接受一个String参数,如果String是表情符号,则返回true,否则返回false

@Test
void givenAWord_whenUsingEmojiJava_thenDetectEmoji(){
    boolean emoji = EmojiManager.isEmoji("\uD83D\uDC3B");
    assertTrue(emoji);

    boolean notEmoji = EmojiManager.isEmoji("w");
    assertFalse(notEmoji);
}

从这个测试可以看出,库正确地识别了代理对作为表情符号,并断言单个字母“w”不是表情符号。

这个库还提供了许多其他功能,因此它是处理Java中表情符号的强大候选者。

4. 使用正则表达式

如前所述,我们知道在Java字符串中表情符号的大致外观,以及代理对可能保留的值范围。第一个代码单元的范围在U+D800U+DBFF之间,第二个代码单元的范围在U+DC00U+DFFF之间。

我们可以利用这些洞察来编写一个正则表达式,用于检查给定的String是否是某个由代理对表示的表情符号。需要注意的是,并非所有代理对都是表情符号,所以这可能会产生误报:

@Test
void givenAWord_whenUsingRegex_thenDetectEmoji(){
    String regexPattern = "[\uD800-\uDBFF\uDC00-\uDFFF]+";
    String emojiString = "\uD83D\uDC3B";
    boolean emoji = emojiString.matches(regexPattern);
    assertTrue(emoji);

    String notEmojiString = "w";
    boolean notEmoji = notEmojiString.matches(regexPattern);
    assertFalse(notEmoji);
}

然而,检查预期范围并不总是那么简单。正如我们之前看到的,有些表情符号仅使用单个代码单元。此外,许多表情符号有附加在末尾的修饰符,会改变表情符号的外观。我们还可以通过在它们之间使用零宽度连接符(ZWJ)组合多个表情符号来形成更复杂的表情。

一个很好的例子是海盗旗表情符号,它可以使用挥舞的黑旗、Skull and Crossbones中间加上ZWJ字符来构建。考虑到这一点,很明显我们需要一个更复杂的正则表达式,以确保我们捕获所有表情符号。

Unicode发布了一份文档详细列出当前的所有表情符号值。我们可以编写解析器处理这份文档,或者将范围提取到自己的配置文件中。然后,这些结果就可以用于我们自己的可靠表情符号查找器。

5. 总结

在这篇文章中,我们探讨了Java如何以UTF-16代理对的形式表示Unicode表情符号。我们介绍了一个名为emoji-java的库,可以在代码中使用它来检测表情符号。这个库提供了一个简单的方法来检查String是否是表情符号。

我们还有选择自己编写检测代码的选项,使用正则表达式。然而,这比较复杂,需要覆盖众多可能的值,而且这个范围还在不断增长。为了成功实现,我们需要能够接受程序外部的Unicode更新。

如往常一样,示例代码的完整版本可在GitHub上找到。