2009-10-29 42 views
7

Tôi đang cố gắng chuyển các tham số từ tầng trung gian PHP sang một chương trình phụ trợ java hiểu J2EE. Tôi đang viết mã điều khiển trong Groovy. Trong đó, tôi đang cố gắng giải mã một số tham số có thể chứa các ký tự quốc tế.giải mã utf-8 trong java

Tôi thực sự bối rối bởi kết quả của việc gỡ lỗi vấn đề này cho đến nay, vì vậy tôi muốn chia sẻ nó với bạn với hy vọng rằng ai đó sẽ có thể đưa ra cách giải thích chính xác kết quả của tôi.

Vì lợi ích của thử nghiệm nhỏ của tôi, thông số tôi chuyển là "déjeuner". Chỉ cần chắc chắn, System.out.println ("déjeuner") mang đến một cách chính xác tôi:

déjeuner 

trong giao diện điều khiển

Bây giờ đây là các/dec và hex giá trị char của mỗi char của chuỗi gốc :

next char: d 100 64 
next char: ? -61 c3 
next char: ? -87 a9 
next char: j 106 6a 
next char: e 101 65 
next char: u 117 75 
next char: n 110 6e 
next char: e 101 65 
next char: r 114 72 

lưu ý rằng chuỗi c3a9 trong UTF-8 là nhân vật muốn-cho: http://www.fileformat.info/info/unicode/char/00e9/index.htm

Bây giờ nếu tôi cố gắng đọc chuỗi này như một chuỗi UTF-8, như trong stmt.ge tBytes ("UTF-8"), tôi đột nhiên kết thúc có một chuỗi 11 byte, như sau:

64 c3 83 c2 a9 6a 65 75 6e 65 72 

trong khi stmt.getBytes ("iso-8859-1") mang lại cho tôi 9 byte:

64 c3 a9 6a 65 75 6e 65 72 

lưu ý trình tự c3a9 tại đây!

bây giờ nếu tôi cố gắng để chuyển đổi chuỗi UTF-8 sang UTF-8, như trong

new String(stmt.getBytes("UTF-8"), "UTF-8"); 

tôi nhận được:

next char: d 100 64 
next char: ? -61 c3 
next char: ? -87 a9 
next char: j 106 6a 
next char: e 101 65 
next char: u 117 75 
next char: n 110 6e 
next char: e 101 65 
next char: r 114 72 

lưu ý trình tự c3a9

khi

new String(stmt.getBytes("iso-8859-1"), "UTF-8") 

kết quả bằng:

lưu ý e9 có trong utf-8 (và ascii), một lần nữa, ký tự 'é' mà tôi mong muốn.

Thật không may, trong cả hai trường hợp, tôi không kết thúc bằng chuỗi thích hợp sẽ hiển thị giống như chuỗi chữ "déjeuner". Kỳ lạ thay, các chuỗi byte cả hai dường như chính xác mặc dù.

Trả lời

9

Khi giao dịch với chuỗi, hãy nhớ: byte! = char. Vì vậy, trong ví dụ đầu tiên của bạn, bạn có char c3, không phải là số byte c3 là sự khác biệt lớn: byte sẽ là một phần của chuỗi UTF-8 nhưng charđã là Unicode. Vì vậy, khi bạn chuyển đổi thành UTF-8, ký tự Unicode c3 phải trở thành trình tự bytec3 83.

Vì vậy, câu hỏi đặt ra là: Bạn đã nhận được chuỗi như thế nào?Phải có một lỗi trong mã đó không xử lý đúng các chuỗi byte được mã hóa UTF-8.

Lý do tại sao ISO-8859-1 thường hoạt động là mã hóa này không sửa đổi bất kỳ char với một điểm mã < 256 (ví dụ: bất cứ điều gì từ 0 đến 255), do đó UTF-8 mã hóa byte chuỗi sẽ không được sửa đổi.

Ví dụ cuối cùng của bạn cũng sai: char e9 là é trong ISO-8859-1 và Unicode. Trong UTF-8, nó không hợp lệ vì nó không phải là byte và do thiếu tiền tố byte c3. Điều đó nói rằng, nó chính xác đại diện cho chuỗi Unicode bạn tìm kiếm.

+0

Cảm ơn câu trả lời rất có nhiều thông tin. Vì vậy, nó nhấn xuống request.getParameter() trong javax.servlet.http.HttpServletRequest để không xử lý đúng các chuỗi byte được mã hóa UTF-8, đúng không? Tôi đã gọi req.setCharacterEncoding ("UTF-8") trên đó. Tôi có thể giải quyết vấn đề gì? Nó vẫn không rõ ràng cho tôi như thế nào tôi nhận được dữ liệu ban đầu cho các thông số của tôi (byte của nó, không ký tự) vì vậy tôi có thể nhận được một số _non-buggy_ String thực hiện để làm việc ra đúng chuỗi UTF ra khỏi nó ... – user162346

+0

Đoán của tôi là người gửi mã hóa dữ liệu bằng UTF-8 nhưng không đặt đúng tiêu đề HTTP cho điều này. –

+0

Vì vậy, hãy đảm bảo rằng phần PHP tạo ra các trang web chỉ định chính xác mã hóa của chúng, đặc biệt là trong biểu mẫu. –

1

Nếu bạn bắt đầu với Chuỗi Java nơi "d\u00C3\u00A9jeuner".equals(stmt) thì dữ liệu đã bị hỏng ở giai đoạn này.

Một Java char không phải là C char. A char trong Java rộng 16bits và chứa hoàn toàn dữ liệu được mã hóa UTF-16. Cố gắng lưu trữ bất kỳ dữ liệu được mã hóa nào khác trong một kiểu Java char/String đang yêu cầu sự cố. Dữ liệu ký tự trong bất kỳ mã hóa nào khác phải là byte dữ liệu.

Nếu bạn đang đọc parameter using the servlet API, thì có khả năng yêu cầu HTTP chứa thông tin mã hóa không nhất quán hoặc không đủ. Kiểm tra mã gọi và tiêu đề HTTP. Có khả năng máy khách đang mã hóa dữ liệu là UTF-8, nhưng servlet giải mã nó là ISO-8859-1.

0

Tôi gặp sự cố rất giống ngoại trừ biểu mẫu của tôi sử dụng yêu cầu "GET" không phải là yêu cầu "POST".

Vì vậy, URL của tôi là một cái gì đó như: http://localhost:4502/form.jsp?query=d%C3%A9jeuner

request.getCharacterEncoding() = ISO-8859-1 
response.getCharacterEncoding() = UTF-8 
request.getParameter("query") = déjeuner 

Vì vậy, nên việc sử dụng HttpServletRequest UTF-8 để giải mã các param yêu cầu (mà rõ ràng nó không phải) hoặc là này chỉ đơn giản là một lỗi trình duyệt vì trình duyệt không không đặt bất kỳ tiêu đề mã hóa ký tự nào (mà lại không có ý nghĩa nhiều vì nó không thực hiện yêu cầu bài đăng). Đây là bộ tiêu đề đầy đủ và chú ý đến% C3% A9 trong URL.

http://localhost:4502/form.jsp?query=d%C3%A9juerne 

GET /form.jsp?query=d%C3%A9juerne HTTP/1.1 
Host: localhost:4502 
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.17) Gecko/2010010604 Ubuntu/9.04 (jaunty) Firefox/3.0.17 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-gb,en;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 300 
Connection: keep-alive 

Vấn đề này tôi thực sự đã sao chép và dán truy vấn vào biểu mẫu trình duyệt và mã hóa nó không chính xác. Cả trong chrome và firefox.

0

Sau khi điều tra thêm, tôi đã tìm thấy câu trả lời này

How to get UTF-8 working in Java webapps?.

Đó là tất cả về cách đặt URIEncoding = "UTF-8" trong trình kết nối tomcat.

Bây giờ để tìm hiểu cách thực hiện điều này trong CMS chúng tôi sử dụng (CQ5/Ngày).

+0

Xin chào, chào mừng bạn đến với Stackoverflow! Xin vui lòng không gửi câu hỏi của riêng như câu trả lời trong câu hỏi của người khác! Họ sẽ bị lạc trong tiếng ồn và không ai trả lời câu hỏi của bạn. Chỉ cần đăng câu hỏi bằng cách nhấp vào nút 'Đặt câu hỏi' ở phía trên cùng bên phải. Sau khi thực hiện điều đó, hãy xóa nhiễu này khỏi chủ đề này. – BalusC