the pdf that you just mentioned 表示范围: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])");
这是两个非捕获组的交替,第一组用于以\uD83C 开头的对,第二组用于以\uD83D 开头的对。
但是失败了(什么也没找到)。我很确定这是因为我们试图在不同的地方指定代理对的 一半:
Pattern p = Pattern.compile("(?:\uD83C[\uDF00-\uDFFF])|(?:\uD83D[\uDC00-\uDDFF])");
// Half of a pair --------------^------^------^-----------^------^------^
我们不能像那样拆分代理对,它们被称为代理pairs是有原因的。 :-)
因此,我认为我们根本不能为此使用正则表达式(或者实际上,任何基于字符串的方法)。我认为我们必须搜索 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;
}
显然,这只是调试级代码,但它确实可以完成工作。 (在您给定的字符串中,带有表情符号,当然它不会找到任何东西,因为它们超出了范围。但是如果您将第二对的上限更改为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());
}
}
}
输出:
\uD83C \uDF00-\uDFFF
\uD83D \uDC00-\uDDFF