普通的substring不能正确截取带Emoji的字符串会导致乱码,这个工具类可以截取。
基本可用,个别情况比如这类“1️⃣”组合Emoji还是会错,据说这个emoji是由:'1'、一个变体选择器和'⃣'组成的。
也可以用str.substring(str.offsetByCodePoints(0, start), str.offsetByCodePoints(0, end))
但是实测发现现在的实现速度更快一些。
package util;
/**
* Emoji字符串工具类
*
* @author [email protected]
* @version 1.0.0 2023-12-21
*/
public class EmojiStringUtil {
private EmojiStringUtil() {
}
/**
* emoji字符串脱敏 - 仅前后各保留一个原文,中间替换为“*”
* @param emojiStr 原始字符串
* @param keepLength 是否保持原长度,保持原长度时中间隐去几个字符就加几个“*”,否则只加一个“*”
* Examples:
* <blockquote><pre>
* masking("hamburger", true) returns "h*******r"
* masking("hamburger", false) returns "h*r"
* </pre></blockquote>
* @return
*/
public static String masking(String emojiStr, boolean keepLength) {
if (emojiStr==null || emojiStr.isEmpty()) {
return "**";
}
int realStringLength = length(emojiStr);
if (realStringLength == 1) {
return emojiStr + "*";
}
String first = substring(emojiStr, 0, 1);
if (realStringLength == 2) {
return first + "*";
}
String last = substring(emojiStr, realStringLength - 1, realStringLength);
// 保持原长度
if (keepLength) {
StringBuilder result = new StringBuilder();
result.append(first);
int fillCount = realStringLength-2;
for (int i=0; i<fillCount; i++) {
result.append("*");
}
result.append(last);
return result.toString();
}
// 不保持原长度
return first + "*" + last;
}
/**
* 能处理emoji表情的substring方法
* @param str 原有的str
* @param beginIndex 起始位置(含)
* @param endIndex 结束位置(不含)
* Examples:
* <blockquote><pre>
* substring("hamburger", 4, 4) returns ""
* substring("hamburger", 4, 8) returns "urge"
* substring("hamburger", 4, 20) returns "urger"
* substring("hamburger", 10, 20) returns ""
* </pre></blockquote>
*/
public static String substring(String str, int beginIndex, int endIndex) {
if (str==null || str.length()==0) {
return str;
}
if (endIndex-beginIndex<=0 || beginIndex>=str.length()) {
return "";
}
int realPosition = 0;
int charStart = -1;
int charEnd = -1;
for (int i = 0; i < str.length(); i++) {
if(charStart==-1 && realPosition==beginIndex) {
charStart = i;
}
if(realPosition==endIndex) {
charEnd = i;
break;
}
int codePoint = str.codePointAt(i);
if (Character.isSupplementaryCodePoint(codePoint)) {
i++;
}
realPosition++;
}
// 未匹配到开始位置时返回空字符
if (charStart==-1){
return "";
}
// 未匹配到结尾时
if (charEnd==-1) {
return str.substring(charStart);
}
return str.substring(charStart, charEnd);
}
/**
* 能处理emoji表情的substring方法
* @param str 原有的str
* @param beginIndex 起始位置(含)
* Examples:
* <blockquote><pre>
* substring("hamburger", 4) returns "urger"
* substring("hamburger", 10) returns ""
* </pre></blockquote>
*/
public static String substring(String str, int beginIndex) {
if (str==null || str.length()==0) {
return str;
}
int realPosition = 0;
int charStart = -1;
for (int i = 0; i < str.length(); i++) {
if(realPosition==beginIndex) {
charStart = i;
break;
}
int codePoint = str.codePointAt(i);
if (Character.isSupplementaryCodePoint(codePoint)) {
i++;
}
realPosition++;
}
// 未匹配到开始位置时返回空字符
if (charStart==-1){
return "";
}
return str.substring(charStart);
}
/**
* 包含emoji表情的字符串的实际长度
* @param str 原有str
* @return str实际长度
*/
public static int length(String str) {
int count = 0;
for (int i = 0; i < str.length(); i++) {
int codePoint = str.codePointAt(i);
if (Character.isSupplementaryCodePoint(codePoint)) {
i++;
}
count++;
}
return count;
}
}