2012-02-13 36 views
15

Vì MySQL 5.1 không hỗ trợ chuỗi UTF-8 4 byte, tôi cần phải thay thế/thả chuỗi 4 byte trong các chuỗi này.Làm thế nào để thay thế/loại bỏ 4 (+) - byte ký tự từ một chuỗi UTF-8 trong Java?

Tôi đang tìm một cách rõ ràng để thay thế các ký tự này.

Thư viện Apache đang thay thế các ký tự có dấu hỏi là tốt cho trường hợp này, mặc dù ASCII tương đương sẽ đẹp hơn, tất nhiên.

N.B. Đầu vào là từ các nguồn bên ngoài (tên e-mail) và nâng cấp cơ sở dữ liệu không phải là một giải pháp tại thời điểm này.

+1

Bạn đang đùa. MySQL vẫn không hỗ trợ Unicode trong ngày và tuổi này? Điều đó không thể chấp nhận được. Giả sử bạn hỗ trợ Unicode khi bạn chỉ có thể xử lý các chuỗi UTF-8 1-, 2 hoặc 3 byte chỉ là lời nói dối lớn khi nói rằng bạn hỗ trợ Unicode khi bạn chỉ hỗ trợ chuỗi ASCII 1 byte. Bạn hỗ trợ bất kỳ điểm mã Unicode hợp pháp nào hoặc bạn không hỗ trợ Unicode. Đó là một điều nhị phân. Âm thanh như MySQL không hỗ trợ Unicode. Hãy cho tôi biết đây là một trò đùa. – tchrist

+2

@tchrist: MySQL 5.5.3 và hỗ trợ đúng UTF-8 thông qua bộ ký tự "utf8mb4" "mới (http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html) . Tuy nhiên, bộ ký tự "utf8" "chỉ hỗ trợ tối đa 3 byte byte UTF-8 ký tự, báo cáo để ngăn chặn các vấn đề sao chép giữa các phiên bản MySQL khác nhau. "utf8" có thể thay đổi thành bí danh cho "utf8mb4" trong bản phát hành MySQL trong tương lai. – ninjalj

+0

Tương tự như [câu hỏi này] (http://stackoverflow.com/questions/8491431/remove-4-byte-characters-from-a-utf-8-string) ngoại trừ nó đang yêu cầu một giải pháp trong PHP thay vì Java. Các chuỗi –

Trả lời

10

Chúng tôi đã kết thúc việc triển khai phương pháp sau trong Java cho vấn đề này. Khái niệm cơ bản thay thế các ký tự bằng một codepoint cao hơn sau đó là 3byte UTF-8 char cuối cùng.

Tính toán bù trừ là để đảm bảo chúng tôi ở lại trên các điểm mã unicode.

public static final String LAST_3_BYTE_UTF_CHAR = "\uFFFF"; 
public static final String REPLACEMENT_CHAR = "\uFFFD"; 

public static String toValid3ByteUTF8String(String s) { 
    final int length = s.length(); 
    StringBuilder b = new StringBuilder(length); 
    for (int offset = 0; offset < length;) { 
     final int codepoint = s.codePointAt(offset); 

     // do something with the codepoint 
     if (codepoint > CharUtils.LAST_3_BYTE_UTF_CHAR.codePointAt(0)) { 
      b.append(CharUtils.REPLACEMENT_CHAR); 
     } else { 
      if (Character.isValidCodePoint(codepoint)) { 
       b.appendCodePoint(codepoint); 
      } else { 
       b.append(CharUtils.REPLACEMENT_CHAR); 
      } 
     } 
     offset += Character.charCount(codepoint); 
    } 
    return b.toString(); 
} 
+0

Cảm ơn bạn. Tôi đã sử dụng điều này để tránh chuyển đổi toàn bộ bộ ký tự MySQL của mình. Tôi không cần nhân vật ngoài hành tinh hay nhân vật poo trong dữ liệu của tôi. – Robert

2

5 chuỗi byte utf-8 bắt đầu bằng chuỗi 111110xx-byte và 6 byte utf-8 bắt đầu bằng 1111110x-byte. Điều quan trọng cần lưu ý là, không có byte theo dõi nào của các chuỗi utf-8 1-byte chứa byte lớn vì các byte tiếp theo luôn có dạng 10xxxxxx.

Vì vậy, bạn chỉ có thể đi qua các byte và mỗi khi bạn thấy một byte loại 111110xx thì chỉ phát ra một '?' đến đầu ra-dòng/mảng trong khi bỏ qua 4 byte tiếp theo từ đầu vào; tương tự cho các chuỗi 6 byte.

+2

5 và 6 byte không hợp lệ trong UTF-8 anyways - đó không phải là để nói rằng chúng không thể xuất hiện trong văn bản nguồn mặc dù. –

+0

có tốt nhất để được an toàn –

+0

nếu 5 và 6 byte trình tự không hợp pháp bất kỳ cách nào họ (nên) được ít hơn của một vấn đề. vấn đề của tôi hiện tại với các chuỗi 4byte là hợp pháp nhưng chưa được hỗ trợ bởi mysql. – pvgoddijn

4

Một giải pháp đơn giản khác là sử dụng cụm từ thông dụng [^\u0000-\uFFFF]. Ví dụ: trong java:

text.replaceAll("[^\\u0000-\\uFFFF]", "\uFFFD"); 
+0

Cảm ơn, câu trả lời xuất sắc – tjeubaoit

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