You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java如何解析错误编码的Unicode数据?

问题描述

用Java解析第三方系统输出的XML文件时,发现<text>节点存在Unicode编码错误:

  • 右单引号’(U+2019)被输出为:<text>â&#128;&#153;</text>,其中â的十六进制字节为C3A2
  • 表情符号💯(U+1F4AF)被输出为:<text>ð&#159;&#146;¯</text>,其中ð的字节为C3B0,¯的字节为C2AF

补充示例输入:

<text>Weâ&#128;&#153;re ð&#159;&#146;¯ going to win</text>

期望输出:We’re 💯 going to win

目前可以手动将&#xxx;转义字符替换为对应字节(如&#128;→0x80,&#153;→0x99),但需要自动检测错误字符、确定受影响长度并替换为正确Unicode字符。

错误原因分析

这是典型的双重编码+实体转义问题,错误生成流程如下:

  1. 原始Unicode字符被编码为UTF-8字节(比如’→E2 82 99,💯→F0 9F 92 AF)
  2. 这些UTF-8字节被错误当作Windows-1252编码的字符读取(比如E2→â,82被转成&#128;实体,99→&#153;实体)
  3. 读取后的字符再次被编码为UTF-8,最终形成错误输出
Java解决方案

核心思路是逆向还原错误流程:先解码HTML实体为对应字节,再将UTF-8编码的字节序列按Windows-1252解码,得到正确字符。

代码实现

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class XmlEncodingFixer {
    // 匹配HTML十进制实体:&#xxx;
    private static final Pattern ENTITY_PATTERN = Pattern.compile("&#(\\d+);");

    public static String fixEncoding(String input) {
        // 步骤1:解码HTML实体为对应字节的字符(将&#xxx;替换为Unicode码点为xxx的字符)
        String decodedEntities = decodeHtmlEntities(input);
        
        // 步骤2:将解码后的字符串转成UTF-8字节序列(还原错误流程中第二次编码的结果)
        byte[] utf8Bytes = decodedEntities.getBytes(StandardCharsets.UTF_8);
        
        // 步骤3:将该字节序列按Windows-1252解码(还原原始的UTF-8字节,再自动转成Unicode)
        return new String(utf8Bytes, Charset.forName("Windows-1252"));
    }

    private static String decodeHtmlEntities(String input) {
        Matcher matcher = ENTITY_PATTERN.matcher(input);
        StringBuilder sb = new StringBuilder();
        while (matcher.find()) {
            int codePoint = Integer.parseInt(matcher.group(1));
            // 将十进制码点转换为对应字符
            matcher.appendReplacement(sb, String.valueOf((char) codePoint));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    public static void main(String[] args) {
        String sampleInput = "Weâ&#128;&#153;re ð&#159;&#146;¯ going to win";
        String fixed = fixEncoding(sampleInput);
        System.out.println(fixed); // 输出:We’re 💯 going to win
    }
}

代码说明

  1. 解码HTML实体:用正则匹配&#xxx;格式的实体,将其转换为对应Unicode码点的字符,还原错误流程中被转义的控制字节
  2. 转UTF-8字节:将解码后的字符串转成UTF-8字节,得到错误流程中第一次错误读取后的字节序列
  3. Windows-1252解码:将该字节序列按Windows-1252解码,还原出原始的UTF-8字节,Java会自动将UTF-8字节转换为正确的Unicode字符

注意事项

  • 确保系统支持Windows-1252编码(Java默认支持)
  • 如果存在其他类型的HTML实体(如&apos;),可以扩展解码逻辑,但当前场景只需要处理十进制实体
  • 对于XML解析,建议先完成XML节点内容的提取,再对文本内容执行上述修复逻辑

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:35:55