UTF-8 编码 java 替换为 3 个十六进制字符

UTF-8 encoding java replacement with 3 hex character

我的应用程序正在从端点接收数据。我对接收到的数据进行一些处理,然后将其插入到数据库中。

在某些时候我遇到了编码问题,因为收到的数据是 UTF-8 而我的数据库使用 LATIN1。显示的错误是:

[org.hibernate.util.JDBCExceptionReporter] ERROR: character with byte sequence 0x2020 in encoding "UTF8" has no equivalent in encoding "LATIN1"

在大多数情况下,我可以通过这样替换来解决:

String text = org.apache.commons.lang.StringUtils.replace(s, "\u2020", "+");

但是现在错误是:

ERROR [org.hibernate.util.JDBCExceptionReporter] ERROR: character with byte sequence 0xe2 0x9c 0xa8 in encoding "UTF8" has no equivalent in encoding "LATIN1"

如何替换这个十六进制? PS:不幸的是,更改数据库编码不是一种选择。这是一个遗留系统。

UTF-8 0xe29ca8sparkles。等同于您已经处理 UTF-8 0x2020 的方式,您可以手动将其替换为类似于三个火花的任何 Latin1 字符(组合)。但是,没有规范的方法可以做到这一点。本质上,您必须检查 0xFF.

以上的所有字符

这里有点奇怪的是您的代码似乎处理 Strings 并且严格来说,Java Strings 始终是 UTF-16。但是,UTF-8 是 UTF-16 的子集,因此可以安全地假设 Java String 可以表示 UTF-8 字符序列。

在您描述的场景中,您通常会接收字节数据并使用 CharsetDecoder to convert UTF-8 byte data to a character string and a CharsetEncoder to convert the character string to Latin1 byte data. Both classes have the method onUnmappableCharacter() 来指定在字符或字节序列在相应编码中没有表示时要采取的操作。将输入接收为 String 消除了控制输入字节编码的可能性,并将输出转发为 String 消除了控制输出字节编码的可能性。

在这种特定情况下,从字符串到 Latin1 字节字符串的转换可能是由数据库驱动程序或数据库本身完成的,似乎无法控制。您可以通过将字符串转换为 Latin1 字节字符串、处理所有不可映射的字符然后将其转换回字符串以将其传递给数据库驱动程序来解决此问题。

感谢您的回答,他们帮助了我。 我意识到我必须分别处理每个编码。 我将用我编写​​的代码来补充答案。

  1. 我做了口音替换(pt-br);
  2. 我将特定编码替换为空白 space;

正如 Izruo 评论的那样,我需要使用 UTF-16 编码。 在我给出的示例 (0xE2 0x9C 0xA8) 中,我应用了替换“\u2728”。在“脸掌”表情符号(编码为 0xF0 0x9F 0xA4 0xA6)中,我应用了两个替换:“\uD83E”和“\uDD26”。

public static void main(String[] args) throws Exception {
    String rawString = "Teste com acentuações";
    byte[] bytes = rawString.getBytes(StandardCharsets.UTF_8);

    String utf8EncodedString = new String(bytes, StandardCharsets.UTF_8);
    System.out.println(convertToLatin1(utf8EncodedString));
}

public static String convertToLatin1(String utf8String) throws Exception {
    if (utf8String == null || utf8String.trim().length() == 0) {
        return UtilString.EMPTY;
    }
    String newString = replaceAccents(utf8String);
    newString = StringUtils.replace(newString, "\u2728", " ");
    newString = StringUtils.replace(newString, "\u277C", " ");
    newString = StringUtils.replace(newString, "\u277D", " ");
    newString = StringUtils.replace(newString, "\u277E", " ");
    newString = StringUtils.replace(newString, "\u277F", " ");
    newString = StringUtils.replace(newString, "\u2665", " ");
    newString = StringUtils.replace(newString, "\u2705", " ");
    newString = StringUtils.replace(newString, "\ud83d", " ");
    newString = StringUtils.replace(newString, "\ude4b", " ");
    newString = StringUtils.replace(newString, "\ud83c", " ");
    newString = StringUtils.replace(newString, "\udffb", " ");
    newString = StringUtils.replace(newString, "\u2340", " ");
    newString = StringUtils.replace(newString, "\u200d", " ");
    newString = StringUtils.replace(newString, "\u2640", " ");
    newString = StringUtils.replace(newString, "\ufe0f", " ");
    newString = StringUtils.replace(newString, "\uD83E", " ");
    newString = StringUtils.replace(newString, "\uDD70", " ");
    newString = StringUtils.replace(newString, "\uDD20", " ");
    newString = StringUtils.replace(newString, "\uDD26", " ");
    
    return newString;
}

private static final String PLAIN_ASCII = "AaEeIiOoUu"    // 
        + "ÁáÉéÍíÓóÚúÝý"  // 
        + "ÂâÊêÎîÔôÛûYy"  // 
        + "ÃãEeIiÕõUuYy"  // 
        + "ÄäËëÏïÖöÜüYy"  // 
        + "Aa"            // 
        + "Çç"            // 
        + "Nn"            // 
;

private static final String UNICODE = "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9" //
        + "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD" //
        + "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177" //
        + "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177" //
        + "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF" //
        + "\u00C5\u00E5" // 
        + "\u00C7\u00E7" // 
        + "\u00D1\u00F1";

public static String replaceAccents(String aString) {
    StringBuilder stringbuilder = new StringBuilder();
    for (int i = 0; i < aString.length(); i++) {
        char c = aString.charAt(i);
        int position = UNICODE.indexOf(c);
        if (position > -1) {
            stringbuilder.append(PLAIN_ASCII.charAt(position));
        } else {
            stringbuilder.append(c);
        }
    }
    return stringbuilder.toString();
}

因此,如果您遇到类似问题,请获取 UTF-16 编码(我在 compart.com 上找到它,但 fileformat.info 没问题)并应用您想要的替换。