将字符串转换为Android JSONObject会丢失utf-8编码

5

我尝试从URL获取一个(JSON格式的)字符串,并将其作为Json对象使用。当我将String转换为JSONObject时,我失去了UTF-8编码。

这是我用来连接到URL并获取字符串的函数:

private static String getUrlContents(String theUrl) {
    StringBuilder content = new StringBuilder();
    try {
        URL url = new URL(theUrl);
        URLConnection urlConnection = url.openConnection();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));

        String line;
        while ((line = bufferedReader.readLine()) != null) {
            content.append(line + "\n");
        }
        bufferedReader.close();
    } catch(Exception e) {
        e.printStackTrace();
    }

    return content.toString();
}

当我从服务器获取数据时,以下代码显示正确的字符:

String output = getUrlContents(url);
Log.i("message1", output);

但是当我将输出字符串转换为JSONObject时,波斯字符变成了问号,像这样??????。(messages是JSON数组中的名称)
JSONObject reader = new JSONObject(output);
String messages = new String(reader.getString("messages").getBytes("ISO-8859-1"), "UTF-8");
Log.i("message2", messages);
4个回答

6
你正在告诉Java使用ISO-8859-1将字符串(键为message)转换为字节,然后从这些字节中创建一个新的字符串,解释为UTF-8。
new String(reader.getString("messages").getBytes("ISO-8859-1"), "UTF-8");

You could simply use:

String messages = reader.getString("messages");

这是有效的,因为通过网络接收到的字节在getUrlContents中已经被正确解释,并且在内部存储为UTF-16字符串。 - toKrause
getUrlContents 仅在服务器的字符编码与客户端相匹配时才起作用。 - Alastair McCormack

1
你可以按照以下方式更新你的代码:

    private static String getUrlContents(String theUrl) {
        StringBuilder content = new StringBuilder();
        try {
            URL url = new URL(theUrl);
            URLConnection urlConnection = url.openConnection();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8"));

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                content.append(line).append("\n");
            }
            bufferedReader.close();
        } catch(Exception e) {
            e.printStackTrace();
        }

        return content.toString().trim();
    }

1
您有两个编码问题:
1. 服务器发送的文本是以某种字符集编码的。当您设置InputStreamReader时,需要传递服务器使用的编码方式,以便正确解码。字符编码通常在Content-type HTTP响应中给出,在charset字段中。JSON通常是UTF-8编码的,但也可以合法地使用UTF-16和UTF-32,因此您需要进行检查。如果没有指定编码方式,则在将字节编组为字符串(反之亦然)时将使用系统环境。基本上,您应该始终指定字符集。
2. 如果您的字符串中包含非ASCII字符,则String messages = new String(reader.getString("messages").getBytes("ISO-8859-1"), "UTF-8"); 显然会导致问题——它将字符串编码为ISO-8995-1,然后尝试将其解码为UTF-8。
可以使用简单的正则表达式模式从Content-type标头中提取charset值,然后再读取输入流。我还包括了一个巧妙的InputStream -> String转换器。
private static String getUrlContents(String theUrl) {

    try {
        URL url = new URL(theUrl);
        URLConnection urlConnection = url.openConnection();
        InputStream is = urlConnection.getInputStream();

        // Get charset field from Content-Type header
        String contentType = urlConnection.getContentType();
        // matches value in key / value pair
        Pattern encodingPattern = Pattern.compile(".*charset\\s*=\\s*([\\w-]+).*");
        Matcher encodingMatcher = encodingPattern.matcher(contentType);
        // set charsetString to match value if charset is given, else default to UTF-8
        String charsetString = encodingMatcher.matches() ? encodingMatcher.group(1) : "UTF-8";

        // Quick way to read from InputStream.
        // \A is a boundary match for beginning of the input
        return new Scanner(is, charsetString).useDelimiter("\\A").next();
    } catch(Exception e) {
        e.printStackTrace();
    }

    return null;
}

0

不确定这是否有帮助,但您可能可以尝试类似以下的操作:

JSONObject result = null;
String str = null;
try 
{           
    str = new String(output, "UTF-8");
    result = (JSONObject) new JSONTokener(str).nextValue();
} 
catch (Exception e) {}

String messages = result.getString("messages");

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