Android - How to filter emoji (emoticons) from a string?
我正在开发一个Android应用,并且我不希望人们在输入中使用表情符号。
如何从字符串中删除表情符号字符?
表情符号可以在以下范围内找到(来源):
- U + 2190至U + 21FF
- U + 2600至U + 26FF
- U + 2700至U + 27BF
- U + 3000至U + 303F
- U + 1F300至U + 1F64F
- U + 1F680至U + 1F6FF
您可以在脚本中使用此行来一次过滤所有内容:
最新的表情符号数据可以在这里找到:
http://unicode.org/Public/emoji/
有一个以表情符号版本命名的文件夹。
作为应用程序开发人员,一个好主意是使用可用的最新版本。
当您查看文件夹内部时,您会在其中看到文本文件。
您应该检查emoji-data.txt。它包含所有标准表情符号代码。
表情符号有很多小的符号代码范围。
最好的支持将是在您的应用程序中检查所有这些。
有人问为什么我们只能在 u后指定4,所以为什么会有5位数字代码。
这些都是由代理对组成的代码。通常使用2个符号来编码一个表情符号。
例如,我们有一个字符串。
1 | String s = ...; |
UTF-16表示
1 | byte[] utf16 = s.getBytes("UTF-16BE"); |
遍历UTF-16
1 | for(int i = 0; i < utf16.length; i += 2) { |
得到一个字符
1 | char c = (char)((char)(utf16[i] & 0xff) << 8 | (char)(utf16[i + 1] & 0xff)); |
现在检查代理对。表情符号位于第一平面上,因此请检查对的第一部分,范围为0xd800..0xd83f。
1 2 3 4 | if(c >= 0xd800 && c <= 0xd83f) { high = c; continue; } |
对于代理对的第二部分,范围是0xdc00..0xdfff。现在我们可以将一对转换为一个5位代码。
1 2 3 4 | else if(c >= 0xdc00 && c <= 0xdfff) { low = c; long unicode = (((long)high - 0xd800) * 0x400) + ((long)low - 0xdc00) + 0x10000; } |
所有其他符号不是成对的,因此请按原样处理它们。
1 2 3 | else { long unicode = c; } |
现在使用emoji-data.txt中的数据检查它是否是emoji。
如果是,则跳过它。如果没有,则将字节复制到输出字节数组。
最后字节数组通过以下方式转换为String
1 | String out = new String(outarray, Charset.forName("UTF-16BE")); |
对于使用Kotlin的用户,Char.isSurrogate也可以提供帮助。查找并从中删除正确的索引。
这是我用来删除表情符号的东西。注意:这仅适用于API 24及更高版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | public String remove_Emojis_For_Devices_API_24_Onwards(String name) { // we will store all the non emoji characters in this array list ArrayList<Character> nonEmoji = new ArrayList<>(); // this is where we will store the reasembled name String newName =""; //Character.UnicodeScript.of () was not added till API 24 so this is a 24 up solution if (Build.VERSION.SDK_INT > 23) { /* we are going to cycle through the word checking each character to find its unicode script to compare it against known alphabets*/ for (int i = 0; i < name.length(); i++) { // currently emojis don't have a devoted unicode script so they return UNKNOWN if (!(Character.UnicodeScript.of(name.charAt(i)) +"").equals("UNKNOWN")) { nonEmoji.add(name.charAt(i));//its not an emoji so we add it } } // we then cycle through rebuilding the string for (int i = 0; i < nonEmoji.size(); i++) { newName += nonEmoji.get(i); } } return newName; } |
so if we pass in a string:
remove_Emojis_For_Devices_API_24_Onwards("?? test ?? Indic:? Japanese:な ?? Korean:?");
it returns: test Indic:? Japanese:な Korean:?
Emoji placement or count doesn't matter