GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

软件研发 --- 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 项目 → 方案三 + 方案四组合使用

posted on 2026-07-28 10:31  GKLBB  阅读(1)  评论(0)    收藏  举报