无法解析并显示从http请求中读取的非utf8字符

时间:2009-11-16 18:22:00

标签: java json parsing encoding

我正在使用Java来解析此请求

http://ajax.googleapis.com/ajax/services/search/web?start=0&rsz=large&v=1.0&q=rz+img+news+recordid+border

结果这个(为了简洁而截断)JSON文件:

{"responseData":{"results":
<...>
"visibleUrl":"www.coolcook.net",
"cacheUrl":"http://www.google.com/search?q\u003dcache:p4Ke5q6zpnUJ:www.coolcook.net",
"title":"مطبخ مطايب - كباب الدجاج والخضار بصلصة الروب",
"titleNoFormatting":"مطبخ مطايب - كباب الدجاج والخضار بصلصة الروب","\u003drz+img+news+recordid+border"}}, 
<...>
"responseDetails": null, "responseStatus": 200}

我的问题在于返回的阿拉伯字符(可能是任何非unicode)。我尝试使用类似的东西将它们转换回unicode:

JSONArray ja = json.getJSONObject("responseData").getJSONArray("results");
JSONObject j = ja.getJSONObject(i);
str = j.getString("titleNoFormatting");
logger.log("before: " + str); // this is just my version of println
enc_str = new String (str.getBytes(), "UTF8");
logger.log("after: " + enc_str);

但是,'before'和'after'结果都是相同的:一组????,无论我是在服务器日志文件中还是在HTML页面中输出它们。还有另一种方法可以取回阿拉伯字符并将其输出到网页中吗?

对于这类问题,JSON是否有任何支持功能可能是为了直接从JSONObject读取非utf字符?

6 个答案:

答案 0 :(得分:7)

您遇到的问题很可能是由于您在谷歌的http响应中读取的字符编码设置不正确造成的。你可以发布实际获取URL的代码并将其解析为JSON对象吗?

作为示例运行以下内容:

public class Test1 {
  public static void main(String [] args) throws Exception {

    // just testing that the console can output the correct chars
    System.out.println("\"title\":\"مطبخ مطايب - كباب الدجاج والخضار بصلصة الروب");

    URL url = new URL("http://ajax.googleapis.com/ajax/services/search/web?start=0&rsz=large&v=1.0&q=rz+img+news+recordid+border");
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    InputStream is  = connection.getInputStream();

    // the important bit is here..........................\/\/\/
    InputStreamReader reader = new InputStreamReader(is, "utf-8");


    StringWriter sw = new StringWriter();

    char [] buffer = new char[1024 * 8];
    int count ;

    while( (count = reader.read(buffer)) != -1){
      sw.write(buffer, 0, count);
    }

    System.out.println(sw.toString());
  }
}

这是使用自时间开始以来一直存在的相当难看的标准URL.openConnection()。如果你使用的是Apache httpclient之类的东西,那么你可以很容易地做到这一点。

关于编码的一些背景阅读,并且可能解释为什么new String (str.getBytes(), "UTF8");将永远无法工作阅读Joel's article on unicode

答案 1 :(得分:2)

我认为JSON.org Java JSON包无法处理UTF8,无论是作为UTF8字符传入还是实际传入\uXXXX代码。我试过两个如下:

import org.json.
public class JsonTest extends TestCase {
    public void testParseText() {
        try {
            JSONObject json1 = new JSONObject("{\"a\":\"\u05dd\"}"); // \u05dd is a Hebrew character
            JSONObject json2 = new JSONObject("{\"a\":\"\\u05dd\"}"); // \u05dd is a Hebrew character
            System.out.println(json1.toString());
            System.out.println(json2.toString());
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

我明白了:

{"a":"?"}
{"a":"?"}

有什么想法吗?

答案 2 :(得分:1)

首先尝试这个:

str = j.getString("titleNoFormatting");
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("c:/test.txt"), "UTF-8"));
writer.write(str);
writer.close();

然后在记事本中打开文件。如果这看起来很好,那么问题在于您的记录器或控制台没有配置为使用UTF-8。否则问题很可能在于您使用的JSON API,它未配置为使用UTF-8

编辑:如果问题实际上在您使用的JSON API中,而您不知道选择哪个,那么我建议您使用Gson。它真的很容易将Json字符串转换为易于使用的javabean。这是一个基本的例子:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;

import com.google.gson.Gson;

public class Test {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://ajax.googleapis.com/ajax/services/search/web"
            + "?start=0&rsz=large&v=1.0&q=rz+img+news+recordid+border");
        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
        GoogleResults results = new Gson().fromJson(reader, GoogleResults.class);

        // Show all results.
        System.out.println(results);

        // Show title of 1st result (is arabic).
        System.out.println(results.getResponseData().getResults().get(0).getTitle());
    }

}

class GoogleResults {

    ResponseData responseData;
    public ResponseData getResponseData() { return responseData; }
    public void setResponseData(ResponseData responseData) { this.responseData = responseData; }
    public String toString() { return "ResponseData[" + responseData + "]"; }

    static class ResponseData {
        List<Result> results;
        public List<Result> getResults() { return results; }
        public void setResults(List<Result> results) { this.results = results; }
        public String toString() { return "Results[" + results + "]"; }
    }

    static class Result {
        private String url;
        private String title;
        public String getUrl() { return url; }
        public String getTitle() { return title; }
        public void setUrl(String url) { this.url = url; }
        public void setTitle(String title) { this.title = title; }
        public String toString() { return "Result[url:" + url +",title:" + title + "]"; }
    }

}

它可以很好地输出结果。希望这会有所帮助。

答案 3 :(得分:1)

问题的重要部分是如何处理HTTP响应的内容。也就是说,你是如何创建json对象的?当您到达原始帖子中的代码时,内容已经损坏。

请求产生UTF-8编码数据。你是如何将其解析为JSON对象的?是否为解码器指定了正确的编码?或者您的平台使用默认字符编码?

答案 4 :(得分:1)

有一个library使用这样的JSon消息保留了http响应(捷克语表达式)的编码:

private static String inputStreamToString(final InputStream inputStream) throws Exception {
 final StringBuilder outputBuilder = new StringBuilder();

 try {
  String string;
  if (inputStream != null) {
   BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
   while (null != (string = reader.readLine())) {
    outputBuilder.append(string).append('\n');
   }
  }
 } catch (Exception ex) {
  throw new Exception("[google-api-translate-java] Error reading translation stream.", ex);
 }

 return outputBuilder.toString();
}

答案很棘手,必须注意几点,主要是平台编码:

afaik影响打印到控制台,从输入流创建文件甚至DB客户端和服务器之间的通信,即使它们都设置为使用utf-8字符集进行编码 - 无论我是否显式创建utf-8字符串,inputstreamReader或者为UTF-8设置JDBC驱动程序,仍然在Linux系统上将$ LANG属性设置为xx_XX.UTF-8,并将附加=“vt.default_utf8 = 1”添加到LILO引导加载程序(在使用它的系统上),必须完成至少对于运行使用utf-8编码文件的数据库和java应用程序的系统。

即使我附加了这个JVM参数-Dfile.encoding = UTF-8,没有平台编码,我在正确编码的流中也没有成功。正确设置JDBC连接器是必要的:“jdbc:mysql:// localhost / DBname?useUnicode = true&amp; characterEncoding = UTF8”,如果要将字符串保存到数据库,该数据库应该处于以下状态:

    mysql> SHOW VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | utf8   |
| character_set_connection | utf8   |
| character_set_database   | utf8   |
| character_set_filesystem | binary |
| character_set_results    | utf8   |
| character_set_server     | utf8   |
| character_set_system     | utf8   |
+--------------------------+--------+

答案 5 :(得分:0)

Google API正确发送UTF-8。我认为问题是您的默认编码无法输出阿拉伯语。检查您的file.encoding媒体资源或获取此类编码,

public static String getDefaultCharSet() throws IOException {
    OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());
    return writer.getEncoding();
}

如果默认编码是ASCII或Latin-1,您将获得“?”。您需要将其更改为UTF-8。