软件研发 --- Java 过滤 Emoji 字符的最佳方案
方案一:使用 Unicode 范围过滤(推荐)
Java
public class EmojiFilter {
/**
* 过滤所有 Emoji 和特殊 Unicode 字符
*/
public static String filterEmoji(String source) {
if (source == null || source.isEmpty()) {
return source;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < source.length(); ) {
int codePoint = source.codePointAt(i);
if (!isEmojiCharacter(codePoint)) {
sb.appendCodePoint(codePoint);
}
i += Character.charCount(codePoint);
}
return sb.toString();
}
/**
* 将 Emoji 替换为指定字符(而不是直接删除)
*/
public static String replaceEmoji(String source, String replacement) {
if (source == null || source.isEmpty()) {
return source;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < source.length(); ) {
int codePoint = source.codePointAt(i);
if (isEmojiCharacter(codePoint)) {
sb.append(replacement);
} else {
sb.appendCodePoint(codePoint);
}
i += Character.charCount(codePoint);
}
return sb.toString();
}
/**
* 判断是否为 Emoji 字符
*/
private static boolean isEmojiCharacter(int codePoint) {
return (codePoint >= 0x2600 && codePoint <= 0x27FF) // 杂项符号、标点
|| (codePoint >= 0x2300 && codePoint <= 0x23FF) // 杂项技术符号
|| (codePoint >= 0x2B50 && codePoint <= 0x2B55) // 星星等
|| (codePoint >= 0x1F300 && codePoint <= 0x1F5FF) // 杂项符号和象形文字
|| (codePoint >= 0x1F600 && codePoint <= 0x1F64F) // 表情符号
|| (codePoint >= 0x1F680 && codePoint <= 0x1F6FF) // 交通和地图
|| (codePoint >= 0x1F700 && codePoint <= 0x1F77F) // 炼金术符号
|| (codePoint >= 0x1F780 && codePoint <= 0x1F7FF) // 几何形状扩展
|| (codePoint >= 0x1F800 && codePoint <= 0x1F8FF) // 补充箭头-C
|| (codePoint >= 0x1F900 && codePoint <= 0x1F9FF) // 补充符号和象形文字
|| (codePoint >= 0x1FA00 && codePoint <= 0x1FA6F) // 象棋符号
|| (codePoint >= 0x1FA70 && codePoint <= 0x1FAFF) // 符号和象形文字扩展-A
|| (codePoint >= 0x20D0 && codePoint <= 0x20FF) // 组合用附加符号
|| (codePoint >= 0xFE00 && codePoint <= 0xFE0F) // 变体选择符
|| (codePoint >= 0x1F1E0 && codePoint <= 0x1F1FF) // 区域指示符(国旗)
|| codePoint == 0x200D // 零宽连接符
|| codePoint == 0xFE0F; // 变体选择符-16
}
/**
* 检测字符串是否包含 Emoji
*/
public static boolean containsEmoji(String source) {
if (source == null || source.isEmpty()) {
return false;
}
for (int i = 0; i < source.length(); ) {
int codePoint = source.codePointAt(i);
if (isEmojiCharacter(codePoint)) {
return true;
}
i += Character.charCount(codePoint);
}
return false;
}
}
方案二:使用正则表达式
Java
public class EmojiRegexFilter {
// 匹配 Emoji 的正则表达式
private static final Pattern EMOJI_PATTERN = Pattern.compile(
"[\\x{1F600}-\\x{1F64F}" + // 表情
"\\x{1F300}-\\x{1F5FF}" + // 杂项符号
"\\x{1F680}-\\x{1F6FF}" + // 交通
"\\x{1F700}-\\x{1F77F}" + // 炼金术
"\\x{1F780}-\\x{1F7FF}" + // 几何
"\\x{1F800}-\\x{1F8FF}" + // 箭头
"\\x{1F900}-\\x{1F9FF}" + // 补充符号
"\\x{1FA00}-\\x{1FA6F}" + // 扩展
"\\x{1FA70}-\\x{1FAFF}" + // 扩展A
"\\x{2600}-\\x{27FF}" + // 杂项
"\\x{2300}-\\x{23FF}" + // 技术
"\\x{FE00}-\\x{FE0F}" + // 变体选择符
"\\x{1F1E0}-\\x{1F1FF}" + // 国旗
"\\u200D" + // 零宽连接符
"]",
Pattern.UNICODE_CHARACTER_CLASS
);
public static String filterEmoji(String source) {
if (source == null) return null;
return EMOJI_PATTERN.matcher(source).replaceAll("");
}
public static String replaceEmoji(String source, String replacement) {
if (source == null) return null;
return EMOJI_PATTERN.matcher(source).replaceAll(replacement);
}
}
方案三:使用第三方库(最全面)
Maven 依赖
XML
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>5.1.1</version>
</dependency>
使用示例
Java
import com.vdurmont.emoji.EmojiParser;
public class EmojiLibFilter {
// 直接移除所有 Emoji
public static String removeEmoji(String source) {
return EmojiParser.removeAllEmojis(source);
}
// 替换为指定字符
public static String replaceEmoji(String source, String replacement) {
return EmojiParser.replaceAllEmojis(source, replacement);
}
// 检测是否包含 Emoji
public static boolean hasEmoji(String source) {
return !EmojiParser.extractEmojis(source).isEmpty();
}
}
方案四:Spring 拦截器(全局处理)
Java
@Component
public class EmojiFilterInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 包装 request,自动过滤参数中的 Emoji
return true;
}
}
/**
* 包装 HttpServletRequest,过滤所有参数
*/
public class EmojiRequestWrapper extends HttpServletRequestWrapper {
public EmojiRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return EmojiFilter.filterEmoji(value);
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values != null) {
return Arrays.stream(values)
.map(EmojiFilter::filterEmoji)
.toArray(String[]::new);
}
return null;
}
}
测试用例
Java
public class EmojiFilterTest {
public static void main(String[] args) {
String[] testCases = {
"Hello 😀 World",
"你好🌍世界🎉",
"测试👨👩👧👦家庭emoji", // 组合 emoji
"Normal text without emoji",
"🏳️🌈彩虹旗", // 国旗 emoji
"text with ❤️ heart"
};
for (String test : testCases) {
System.out.println("原始: " + test);
System.out.println("过滤: " + EmojiFilter.filterEmoji(test));
System.out.println("替换: " + EmojiFilter.replaceEmoji(test, "[emoji]"));
System.out.println("含有Emoji: " + EmojiFilter.containsEmoji(test));
System.out.println("---");
}
}
}
方案对比
| 方案 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| Unicode 范围 | 无依赖、性能好 | 需手动维护范围 | 通用项目 |
| 正则表达式 | 简洁 | 复杂 emoji 可能漏过 | 简单场景 |
| emoji-java 库 | 最全面准确 | 增加依赖 | 高准确性要求 |
| Spring 拦截器 | 全局处理 | 仅适用 Web | Spring 项目 |
推荐选择
- 简单项目 → 方案一(Unicode 范围)
- 高准确性 → 方案三(emoji-java 库)
- Spring Web 项目 → 方案三 + 方案四组合使用
免责声明
本文档所有内容仅供安全研究、学术交流与技术学习使用,严禁用于任何未经授权的逆向破解、网络攻击、隐私窃取、恶意软件开发及其他违反《中华人民共和国网络安全法》《数据安全法》等法律法规的行为,使用者应确保已获得目标软件权利人的合法授权并自行承担因使用本文档内容所产生的一切法律责任与后果,作者不对任何直接或间接损害承担任何责任,继续阅读即视为您已知悉并同意上述全部条款。
浙公网安备 33010602011771号