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+D800
到U+DBFF
之间,第二个代码单元的范围在U+DC00
到U+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上找到。