2012-02-15 8 views
8

Với đoạn mã sau:Làm cách nào để phân tích biểu diễn UTF-8 thành Chuỗi trong Java?

String tmp = new String("\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a"); 

String result = convertToEffectiveString(tmp); // result contain now "hello\n" 

Liệu JDK đã cung cấp một số lớp học để làm điều này? Có một libray thực hiện việc này không? (tốt nhất là dưới maven)

Tôi đã thử với ByteArrayOutputStream không thành công.

+3

Đó không phải là UTF-8; đó chỉ là một chuỗi có chứa sự biểu diễn của Unicode thoát. –

Trả lời

3

này hoạt động, nhưng chỉ với ASCII. Nếu bạn sử dụng các ký tự unicode ngoài phạm vi ASCCI, thì bạn sẽ có vấn đề (vì mỗi ký tự được nhồi vào một byte, thay vì một từ đầy đủ được cho phép bởi UTF-8). Bạn có thể thực hiện việc định kiểu dưới đây bởi vì bạn biết rằng UTF-8 sẽ không tràn một byte nếu bạn đảm bảo rằng đầu vào về cơ bản là ASCII (như bạn đã đề cập trong các nhận xét của mình).

package sample; 

import java.io.UnsupportedEncodingException; 

public class UnicodeSample { 
    public static final int HEXADECIMAL = 16; 

    public static void main(String[] args) { 

     try { 
      String str = "\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a"; 

      String arr[] = str.replaceAll("\\\\u"," ").trim().split(" "); 
      byte[] utf8 = new byte[arr.length]; 

      int index=0; 
      for (String ch : arr) { 
       utf8[index++] = (byte)Integer.parseInt(ch,HEXADECIMAL); 
      } 

      String newStr = new String(utf8, "UTF-8"); 
      System.out.println(newStr); 

     } 
     catch (UnsupportedEncodingException e) { 
      // handle the UTF-8 conversion exception 
     } 
    } 
} 

Đây là giải pháp khác khắc phục sự cố chỉ hoạt động với các ký tự ASCII. Điều này sẽ làm việc với bất kỳ ký tự unicode nào trong phạm vi UTF-8 thay vì ASCII chỉ trong 8 bit đầu tiên của dải ô. Nhờ lừa dối cho các câu hỏi. Bạn làm cho tôi suy nghĩ thêm về vấn đề và giải pháp.

package sample; 

import java.io.UnsupportedEncodingException; 
import java.util.ArrayList; 

public class UnicodeSample { 
    public static final int HEXADECIMAL = 16; 

    public static void main(String[] args) { 

     try { 
      String str = "\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a\\u3fff\\uf34c"; 

      ArrayList<Byte> arrList = new ArrayList<Byte>(); 
      String codes[] = str.replaceAll("\\\\u"," ").trim().split(" "); 

      for (String c : codes) { 

       int code = Integer.parseInt(c,HEXADECIMAL); 
       byte[] bytes = intToByteArray(code); 

       for (byte b : bytes) { 
        if (b != 0) arrList.add(b); 
       } 
      } 

      byte[] utf8 = new byte[arrList.size()]; 
      for (int i=0; i<arrList.size(); i++) utf8[i] = arrList.get(i); 

      str = new String(utf8, "UTF-8"); 
      System.out.println(str); 
     } 
     catch (UnsupportedEncodingException e) { 
      // handle the exception when 
     } 
    } 

    // Takes a 4 byte integer and and extracts each byte 
    public static final byte[] intToByteArray(int value) { 
     return new byte[] { 
       (byte) (value >>> 24), 
       (byte) (value >>> 16), 
       (byte) (value >>> 8), 
       (byte) (value) 
     }; 
    } 
} 
+1

"Ký tự Unicode khác với UTF-8" là gì? Làm thế nào một ký tự Unicode/UTF-8 được "nhồi vào một byte"? Tôi không biết nếu bạn có ý nghĩa đúng và không thể hiện rõ ràng, nhưng điều đó hầu như không chính xác. – deceze

+0

Nếu bạn sử dụng một ký tự unicode khác được đặt trong chuỗi "str" ​​ngoài UTF-8, mã này có thể không hoạt động. UTF-8 vẫn đang sử dụng 8 bit, trong đó các bộ ký tự unicode khác có thể (có thể) sử dụng nhiều hơn 8 bit (tất cả 16 bit thay thế). http://www.joelonsoftware.com/articles/Unicode.html – jmq

+0

Rõ ràng, trong trường hợp chung, mã này là không đủ. Nhưng trong trường hợp của tôi, đầu vào được đảm bảo hoàn toàn có thể chuyển đổi sang ASCII. – Stephan

3

Thứ nhất, bạn chỉ đang cố gắng phân tích cú pháp một chuỗi chữ, hoặc là tmp sẽ là một số dữ liệu do người dùng nhập?

Nếu điều này có nghĩa là chuỗi chữ (tức là chuỗi được mã hóa cứng), nó có thể được mã hóa bằng cách sử dụng tính năng thoát Unicode. Trong trường hợp của bạn, điều này chỉ có nghĩa là sử dụng dấu xồ nguợc duy nhất thay vì backslashes kép:

String result = "\u0068\u0065\u006c\u006c\u006f\u000a"; 

Tuy nhiên, nếu bạn cần phải sử dụng quy tắc chuỗi phân tích cú pháp của Java để phân tích đầu vào người sử dụng, một điểm khởi đầu tốt có thể là phương pháp Apache Commons Lang StringEscapeUtils.unescapeJava() .

1

Tôi chắc rằng có phải là một cách tốt hơn, nhưng chỉ sử dụng JDK:

public static String handleEscapes(final String s) 
{ 
    final java.util.Properties props = new java.util.Properties(); 
    props.setProperty("foo", s); 
    final java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); 
    try 
    { 
     props.store(baos, null); 
     final String tmp = baos.toString().replace("\\\\", "\\"); 
     props.load(new java.io.StringReader(tmp)); 
    } 
    catch(final java.io.IOException ioe) // shouldn't happen 
     { throw new RuntimeException(ioe); } 
    return props.getProperty("foo"); 
} 

sử dụng java.util.Properties.load(java.io.Reader) để xử lý các dấu chéo ngược-thoát (sau khi đầu tiên sử dụng java.util.Properties.store(java.io.OutputStream, java.lang.String) để xuyệc ngược-thoát khỏi bất cứ điều gì mà có thể gây ra sự cố trong tệp thuộc tính và sau đó sử dụng replace("\\\\", "\\") để đảo ngược dấu gạch chéo ngược-thoát của dấu gạch chéo ngược ban đầu).

(Disclaimer:. Mặc dù tôi đã kiểm tra tất cả các trường hợp tôi có thể nghĩ ra, vẫn còn một số lẽ mà tôi không nghĩ đến)