2010-12-18 14 views
15

मेरे पास एक वेब पेज से पकड़े गए JSON सरणी के साथ अजीब वर्ण एन्कोडिंग समस्याएं हैं। सर्वर इस हेडर को वापस भेज रहा है:एंड्रॉइड जावा यूटीएफ -8 एचटीपी क्लाइंट समस्या

सामग्री-प्रकार टेक्स्ट/जावास्क्रिप्ट; charset = UTF-8

इसके अलावा मैं फ़ायरफ़ॉक्स में JSON आउटपुट या किसी भी ब्राउज़र और यूनिकोड वर्णों को ठीक से प्रदर्शित कर सकता हूं। प्रतिक्रिया में कभी-कभी उच्चारण भाषा के साथ किसी अन्य भाषा के शब्द होते हैं। हालांकि, जब मैं इसे नीचे खींचता हूं और इसे जावा में एक स्ट्रिंग में डालता हूं तो मुझे उन अजीब प्रश्न चिह्न मिल रहे हैं।

HttpParams params = new BasicHttpParams(); 
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
HttpProtocolParams.setContentCharset(params, "utf-8"); 
params.setBooleanParameter("http.protocol.expect-continue", false); 

HttpClient httpclient = new DefaultHttpClient(params); 

HttpGet httpget = new HttpGet("http://www.example.com/json_array.php"); 
HttpResponse response; 
    try { 
     response = httpclient.execute(httpget); 

     if(response.getStatusLine().getStatusCode() == 200){ 
      // Connection was established. Get the content. 

      HttpEntity entity = response.getEntity(); 
      // If the response does not enclose an entity, there is no need 
      // to worry about connection release 

      if (entity != null) { 
       // A Simple JSON Response Read 
       InputStream instream = entity.getContent(); 
       String jsonText = convertStreamToString(instream); 

       Toast.makeText(getApplicationContext(), "Response: "+jsonText, Toast.LENGTH_LONG).show(); 

      } 

     } 


    } catch (MalformedURLException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: Malformed URL - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } catch (IOException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: IO Exception - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } catch (JSONException e) { 
     Toast.makeText(getApplicationContext(), "ERROR: JSON - "+e.getMessage(), Toast.LENGTH_LONG).show(); 
     e.printStackTrace(); 
    } 

private static String convertStreamToString(InputStream is) { 
    /* 
    * To convert the InputStream to String we use the BufferedReader.readLine() 
    * method. We iterate until the BufferedReader return null which means 
    * there's no more data to read. Each line will appended to a StringBuilder 
    * and returned as String. 
    */ 
    BufferedReader reader; 
    try { 
     reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); 
    } catch (UnsupportedEncodingException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    StringBuilder sb = new StringBuilder(); 

    String line; 
    try { 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return sb.toString(); 
} 

आप देख सकते हैं, मैं InputStreamReader के UTF-8 को निर्दिष्ट कर रहा हूँ, लेकिन हर बार जब मैं टोस्ट के माध्यम से लौटे JSON टेक्स्ट देखने यह अजीब प्रश्न चिह्न है: यहाँ मेरी कोड है। मैं सोच रहा हूं कि मुझे इनपुटस्ट्रीम को बाइट [] के बजाय भेजने की ज़रूरत है?

किसी भी मदद के लिए अग्रिम धन्यवाद।

if (entity != null) { 
    // A Simple JSON Response Read 
    // InputStream instream = entity.getContent(); 
    // String jsonText = convertStreamToString(instream); 

    String jsonText = EntityUtils.toString(entity, HTTP.UTF_8); 

    // ... toast code here 
} 

उत्तर

37

इस प्रयास करें। लेकिन मैं आपके convertStreamToString कोड के साथ कुछ भी स्पष्ट रूप से गलत नहीं देख सकता।

मेरे अनुमान कर रहे हैं:

  1. सर्वर धारा के शुरू में एक UTF बाइट आदेश मार्क (बीओएम) रहा है। मानक जावा यूटीएफ -8 वर्ण डिकोडर बीओएम को नहीं हटाता है, इसलिए संभावना है कि यह परिणामी स्ट्रिंग में समाप्त हो जाएगा। (हालांकि, EntityUtils के लिए कोड बीओएम के साथ कुछ भी नहीं प्रतीत होता है।)
  2. आपका convertStreamToString चरित्र स्ट्रीम को एक समय में एक पंक्ति को पढ़ रहा है, और हार्ड-वायर्ड '\n' का उपयोग करके इसे फिर से इकट्ठा कर रहा है- लाइन मार्कर यदि आप इसे बाहरी फ़ाइल या एप्लिकेशन में लिखने जा रहे हैं, तो आपको शायद प्लेटफ़ॉर्म विशिष्ट एंड-ऑफ़-लाइन मार्कर का उपयोग करना चाहिए।
+0

प्रतिक्रिया के लिए धन्यवाद:

private static String extractCharsetFromContentType(String contentType) { if (TextUtils.isEmpty(contentType)) return null; Pattern p = Pattern.compile(".*charset=([^\\s^;^,]+)"); Matcher m = p.matcher(contentType); if (m.find()) { try { return m.group(1); } catch (Exception e) { return null; } } return null; } 

फिर बनाने के लिए InputStreamReader निकाले चारसेट का उपयोग करें। मैंने आपके परिवर्तन जोड़े और EntityUtils के लिए अतिरिक्त अपाचे सामग्री आयात की लेकिन अब ऐप केवल EntityUtils.toString लाइन पर अप्रत्याशित रूप से समाप्त हो जाता है। प्रोग्राम संकलित करता है और चलता है, लेकिन क्या मुझे स्ट्रिंग को कॉल करने से पहले इकाई को कुछ करने की ज़रूरत है? –

+0

कोई बात नहीं। मैं एक मूर्ख था और मेरे यूआरएल के साथ कुछ गड़बड़ कर दिया। यह काम करता हैं! पात्रों को सही ढंग से प्रस्तुत किया जाता है! –

+3

@ माइकल: यह जवाब बहुत अच्छा है और अगर मैं सवाल पूछता तो मैं इसे स्वीकार करूंगा। – SK9

5

@ Arhimed के जवाब समाधान है:

1

यह सिर्फ इतना है कि आपका कन्वर्टस्ट्रीम टॉस्ट्रिंग HttpRespnose में एन्कोडिंग सेट का सम्मान नहीं कर रहा है। यदि आप EntityUtils.toString(entity, HTTP.UTF_8) के अंदर देखते हैं, तो आप देखेंगे कि EntityUtils पता लगाता है कि पहले HttpResponse में एन्कोडिंग सेट है या नहीं, तो यदि एंटीटी उपयोग उस एन्कोडिंग का उपयोग करता है। यह केवल पैरामीटर में पारित एन्कोडिंग पर वापस आ जाएगा (इस मामले में HTTP.UTF_8) यदि इकाई में एन्कोडिंग सेट नहीं है।

तो आप कह सकते हैं कि आपका HTTP.UTF_8 पैरामीटर में पारित किया गया है लेकिन यह कभी भी उपयोग नहीं किया जाता क्योंकि यह गलत एन्कोडिंग है। तो यहां EntityUtils से सहायक विधि के साथ आपके कोड में अपडेट किया गया है।

  HttpEntity entity = response.getEntity(); 
      String charset = getContentCharSet(entity); 
      InputStream instream = entity.getContent(); 
      String jsonText = convertStreamToString(instream,charset); 

    private static String getContentCharSet(final HttpEntity entity) throws ParseException { 
    if (entity == null) { 
     throw new IllegalArgumentException("HTTP entity may not be null"); 
    } 
    String charset = null; 
    if (entity.getContentType() != null) { 
     HeaderElement values[] = entity.getContentType().getElements(); 
     if (values.length > 0) { 
      NameValuePair param = values[0].getParameterByName("charset"); 
      if (param != null) { 
       charset = param.getValue(); 
      } 
     } 
    } 
    return TextUtils.isEmpty(charset) ? HTTP.UTF_8 : charset; 
} 



private static String convertStreamToString(InputStream is, String encoding) { 
    /* 
    * To convert the InputStream to String we use the 
    * BufferedReader.readLine() method. We iterate until the BufferedReader 
    * return null which means there's no more data to read. Each line will 
    * appended to a StringBuilder and returned as String. 
    */ 
    BufferedReader reader; 
    try { 
     reader = new BufferedReader(new InputStreamReader(is, encoding)); 
    } catch (UnsupportedEncodingException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    StringBuilder sb = new StringBuilder(); 

    String line; 
    try { 
     while ((line = reader.readLine()) != null) { 
      sb.append(line + "\n"); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
    return sb.toString(); 
} 
0

आर्किमिड का जवाब सही है। हालांकि, कि HTTP अनुरोध में एक अतिरिक्त हैडर प्रदान करके बस किया जा सकता है:

Accept-charset: utf-8 

कुछ भी हटाने या किसी अन्य लाइब्रेरी का उपयोग करने की आवश्यकता नहीं है।

उदाहरण के लिए,

GET/HTTP/1.1 
Host: www.website.com 
Connection: close 
Accept: text/html 
Upgrade-Insecure-Requests: 1 
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.10 Safari/537.36 
DNT: 1 
Accept-Encoding: gzip, deflate, sdch 
Accept-Language: en-US,en;q=0.8 
Accept-Charset: utf-8 

अधिकांश शायद आपके अनुरोध किसी भी Accept-Charset हैडर जरूरत नहीं है।

0

प्रतिक्रिया सामग्री प्रकार फ़ील्ड से वर्णमाला निकालें। ऐसा करने के लिए निम्न विधि का उपयोग कर सकते हैं:

String charsetName = extractCharsetFromContentType(connection.getContentType()); 

InputStreamReader inReader = (TextUtils.isEmpty(charsetName) ? new InputStreamReader(inputStream) : 
        new InputStreamReader(inputStream, charsetName)); 
      BufferedReader reader = new BufferedReader(inReader); 
संबंधित मुद्दे