有没有一种方法可以修复错误编码的字符串?

3

我通过消息代理(Stomp)获取了这个字符串:

João

这就是它应该的样子:

João

有没有办法在Java中还原它?!谢谢!

1
请参见https://dev59.com/z3E85IYBdhLWcg3wwWat,该链接涉及Java中的字符串编码问题。 - user219882
消息代理(ActiveMQ)...问题是我不能触及代码的另一侧,我只需要修复这个字符串... - joaoricardo000
2
我们需要知道您获取数据的方式(在哪里,使用什么编程语言等),以确定他们发送的数据是否不正确或者您是否错误地解释了它。 - dfb
1
@JRicardo000:你是如何获取数据的?如果你获取的是二进制数据并将其转换为文本,那么很可能只需要更改你用于该转换的编码方式。 - Jon Skeet
2个回答

4
U+00C3  Ã   c3 83   LATIN CAPITAL LETTER A WITH TILDE
U+00C2  Â   c3 82   LATIN CAPITAL LETTER A WITH CIRCUMFLEX
U+00A3  £   c2 a3   POUND SIGN
U+00E3  ã   c3 a3   LATIN SMALL LETTER A WITH TILDE

我很难确定这是否是一个数据(编码)转换问题。这些数据可能只是有问题吗?

如果数据没有问题,那么我们必须假设您正在错误地解释编码。我们不知道原始编码,并且除非您做了一些不同的事情,否则Java的默认编码为UTF-16。我不明白在任何常见编码中编码的João如何被解释为UTF-16中的João

为了确保,我用这个Python脚本来检查,没有找到匹配项。就我而言,我不完全确定它是否涵盖了所有编码或者是否缺少了某些角落的情况。

#!/usr/bin/env python                                                                                                                   
# -- coding: utf-8 --                                                                                                                   
import pkgutil
import encodings

good = u'João'
bad = u'João'

false_positives = set(["aliases"])

found = set(name for imp, name, ispkg in pkgutil.iter_modules(encodings.__path__) if not ispkg)
found.difference_update(false_positives)
print found


for x in found:
    for y in found:
        res = None
        try:
            res =  good.encode(x).decode(y)
            print res,x,y
        except:
            pass
        if not res is None:
            if res == bad:
                print "FOUND"
                exit(1)

谢谢你的回答,我很感激你的努力。但是我还是必须改变代码的另一侧。我只是在想是否有什么简单的方法可以避免这样做呢,呵呵。 - joaoricardo000

2
在某些情况下,黑客攻击是有效的。但最好的方法是防止它发生。
我曾经遇到过这个问题,当我有一个servlet在页面上正确打印了正确的标题和http内容类型和编码时,IE会提交使用latin1而不是正确的编码方式进行编码的表单。所以我创建了一个快速脏的hack(涉及检测并转换是否确实是IE的请求包装器)来修复新数据,这个方法运行良好。对于已经混乱的数据库中的数据,我使用了以下hack。
不幸的是,我的hack不能完美地解决你的示例字符串,但它看起来非常接近(与我“理论原因”再现的破碎字符串相比,只多了一个Ã)。所以也许我的“latin1”的猜测是错误的,你应该尝试其他的(比如Tomas发布的那个链接中提到的)。
package peter.test;

import java.io.UnsupportedEncodingException;

/**
* User: peter
* Date: 2012-04-12
* Time: 11:02 AM
*/
public class TestEncoding {
    public static void main(String args[]) throws UnsupportedEncodingException {
        //In some cases a hack works. But best is to prevent it from ever happening.
        String good = "João";
        String bad = "João";

        //this line demonstrates what the "broken" string should look like if it is reversible.
        String broken = breakString(good, bad);

        //here we show that it is fixable if broken like breakString() does it.
        fixString(good, broken);

        //this line attempts to fix the string, but it is not fixable unless broken in the same way as breakString()
        fixString(good, bad);
    }

    private static String fixString(String good, String bad) throws UnsupportedEncodingException {
        byte[] bytes = bad.getBytes("latin1"); //read the Java bytes as if they were latin1 (if this works, it should result in the same number of bytes as java characters; if using UTF8, it would be more bytes)
        String fixed = new String(bytes, "UTF8"); //take the raw bytes, and try to convert them to a string as if they were UTF8

        System.out.println("Good: " + good);
        System.out.println("Bad: " + bad);
        System.out.println("bytes1.length: " + bytes.length);
        System.out.println("fixed: " + fixed);
        System.out.println();

        return fixed;
    }

    private static String breakString(String good, String bad) throws UnsupportedEncodingException {
        byte[] bytes = good.getBytes("UTF8");
        String broken = new String(bytes, "latin1");

        System.out.println("Good: " + good);
        System.out.println("Bad: " + bad);
        System.out.println("bytes1.length: " + bytes.length);
        System.out.println("broken: " + broken);
        System.out.println();

        return broken;
    }
}

以下是使用Sun jdk 1.7.0_03的结果:

Good: João
Bad: João
bytes1.length: 5
broken: João

Good: João
Bad: João
bytes1.length: 5
fixed: João

Good: João
Bad: João
bytes1.length: 6
fixed: Jo�£o

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接