Невозможно проанализировать и отобразить символы не-utf8, прочитанные из запроса http - PullRequest
8 голосов
/ 16 ноября 2009

Я использую 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, используя что-то вроде:

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);

Однако результаты «до» и «после» одинаковы: набор значений независимо от того, выводю ли я их в файл журнала сервера или на страницу HTML. Есть ли другой способ вернуть арабские символы и вывести их на веб-страницу?

Есть ли в JSON вспомогательные функции для решения этой проблемы, возможно, для того, чтобы читать символы не-utf сразу из JSONObject?

Ответы [ 6 ]

7 голосов
/ 16 ноября 2009

Скорее всего, ваша проблема вызвана неправильной настройкой кодировки символов в точке, которую вы читаете в ответе http от Google. Можете ли вы опубликовать код, который фактически получает 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"); никогда не будет работать, прочитайте статью Джоэла о юникоде

2 голосов
/ 09 июня 2010

Я думаю, что JSON-пакет Java JSON.org не может обрабатывать 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":"?"}

Есть идеи?

1 голос
/ 16 сентября 2010

Существует библиотека , которая сохраняет кодировку ответа http (чешские выражения) с сообщением JSon, например:

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 влияет на печать на консоль, на создание файлов из входного потока и даже на связь между клиентом и сервером БД, даже если они оба настроены на использование кодировки utf-8 для кодирования - независимо от того, создаю я явно строку utf-8, inputtreamReader или установите драйвер JDBC для UTF-8, все еще устанавливая свойство $ LANG для xx_XX.UTF-8 в системах linux и добавьте append = "vt.default_utf8 = 1" в загрузчик LILO (в системах, которые его используют) по крайней мере, для систем, работающих с базами данных и Java-приложениями, работающими с файлами в кодировке utf-8.

Даже если я добавлю этот параметр JVM -Dfile.encoding = UTF-8, без кодирования платформы мне не удалось правильно закодировать потоки. Необходимо правильно настроить JDBC-коннектор: «jdbc: mysql: // localhost / DBname? UseUnicode = true & 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   |
+--------------------------+--------+
1 голос
/ 16 ноября 2009

Важной частью проблемы является то, как вы обрабатываете содержимое HTTP-ответа. То есть как вы создаете объект json? К тому времени, когда вы дойдете до кода в исходном сообщении, содержимое уже повреждено.

В результате запроса получаются данные в кодировке UTF-8. Как вы разбираете его в JSON-объекты? Правильная ли кодировка указана декодеру? Или используется кодировка символов по умолчанию вашей платформы?

1 голос
/ 16 ноября 2009

Сначала попробуйте это:

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 + "]"; }
    }

}

Хорошо выводит результаты. Надеюсь, это поможет.

0 голосов
/ 16 ноября 2009

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...