2013-07-08 32 views
6

Tôi đang cố gắng tìm phương thức chuỗi con hoặc phương thức characterAt hoạt động trên chuỗi có chứa văn bản được mã hóa UTF-8 trong JAVA.Chuỗi con hoặc phương thức CharacterAt cho chuỗi UTF8 có 2+ byte trong JAVA

Nội bộ, JAVA hoạt động với UTF-16. Điều này có nghĩa là một String bao gồm các ký tự có kích thước là 2 byte. Một ký tự UTF-8 có thể có kích thước tối đa 6 byte. Khi JAVA lưu trữ nó bên trong một String, nó tách ký tự UTF-8 trên nhiều ký tự.

Ví dụ: Nhân vật U + 20000 (UTF-8 Hex: F0 A0 80 80) được lưu trữ nội bộ trong JAVA như một String với hai ký tự (UTF-16 Hex: D840 và DC00).

Khi bạn có Chuỗi chứa ký tự UTF-8 4 byte và sử dụng độ dài, câu trả lời là "2". Khi bạn sử dụng chuỗi con (0,1), bạn sẽ nhận được nửa đầu của ký tự.

Một số mã để minh họa điều này:

ByteBuffer inputBuffer = ByteBuffer.wrap(new byte[]{(byte)0xF0, (byte)0xA0, (byte)0x80, (byte)0x80}); 
    CharBuffer data = Charset.forName("UTF-8").decode(inputBuffer); 
    String string_test = data.toString(); 
    int length = string_test.length(); 
    String first_half = string_test.substring(0, 1); 
    String second_half = string_test.substring(1, 2); 
    String full_character = string_test.substring(0, 2); 

Tất cả điều này, ngay cả khi bất ngờ, không phải là một lỗi, vì JAVA làm việc trong UTF-16. Hỗ trợ UTF-8 vốn có sẽ tốt đẹp. Nhưng nó không có ở đó.

JAVA có lớp học nào trong thư viện mặc định hay lớp học tồn tại ở đâu đó cung cấp hỗ trợ UTF-8 không? Như trong:

  • utf8string.length() - trả về 1 nếu có nhân vật một 4 byte trong
  • utf8string.getCharacterAt (0) - trả về ký tự đầu tiên, không phải là nửa đầu của nó .
  • utf8string.substring (0,1) - trả về ký tự đầu tiên, chứ không phải nửa đầu tiên.

Hoặc, giải pháp thường được sử dụng cho điều này là gì? Chuyển đổi tất cả các ký tự UTF-8 không được hỗ trợ UTF-16 thành một ký tự UTF-16 mặc định khi đọc các tệp UTF-8? Và, kết quả là, mất tất cả thông tin về các ký tự trong phạm vi điểm mã hóa mà UTF-16 không hỗ trợ? Đó không nhất thiết là một vấn đề trong việc thực hiện cụ thể của tôi, vì vậy nếu có một cách phổ biến để làm điều này, tôi muốn được quan tâm.

Trả lời

7

JAVA có lớp nào trong thư viện mặc định hay lớp học tồn tại ở đâu đó cung cấp hỗ trợ UTF-8 không?

Bạn không thực sự hỗ trợ UTF-8. Bạn đang theo các điểm mã Unicode (số nguyên 32 bit), thay vì các đơn vị mã UTF-16. Và có, Java cung cấp hỗ trợ cho điều này, nhưng nó không phải là cực kỳ dễ dàng để làm việc với.

Ví dụ, để có được một điểm mã đặc biệt, sử dụng String.codePointAt - mang trong tâm trí rằng chỉ số mà bạn cung cấp là về UTF-16 đơn vị mã, không điểm mã.

Để tìm độ dài trong các điểm mã, hãy sử dụng String.codePointCount.

Để tìm chuỗi con, bạn cần phải tìm bù đắp theo đơn vị mã UTF-16, sau đó sử dụng phương thức bình thường substring; sử dụng String.offsetByCodePoints để tìm chỉ mục phù hợp.

Về cơ bản, hãy xem qua API String ở tất cả các phương pháp có chứa codePoint.

+0

Cảm ơn, đã trả lời phần đầu tiên của câu hỏi của tôi. Đối với phần thứ hai, tôi đã sử dụng http://stackoverflow.com/questions/12867000/how-to-remove-surrogate-characters-in-java. Vì tôi không muốn có những nhân vật trong những codepoints phức tạp hoạt động chuỗi của tôi. – Wouter

+0

Ngoài ra, đối với những người khác có thể -need- tất cả các điểm mã, có thể thú vị khi xem: http://avro.apache.org/docs/1.6.1/api/java/org/apache/avro /util/Utf8.html – Wouter

+0

Vì vậy, nó là điều này cho chuỗi con? public static String substringUtf8 (String utf8String, int from, int to) { trả về utf8String.substring (utf8String.offsetByCodePoints (0, from), utf8String.offsetByCodePoints (0, đến));} – RobertG

0

Những gì bạn cần tìm là hỗ trợ gốc của Java cho UTF-32. Xem các phương thức String#*codePoint*, chẳng hạn như codePointAt.

Các vấn đề liên quan