2012-02-13 84 views
15

因爲MySQL 5.1不支持4字節的UTF-8序列,我需要替換/刪除這些字符串中的4字節序列。如何在Java中使用UTF-8字符串替換/刪除4(+)字節的字符?

我正在尋找一種乾淨的方式來替換這些字符。

Apache庫正在用一個問號替換字符,這種情況很好,儘管當然ASCII等效將更好。

N.B.輸入來自外部來源(電子郵件名稱),此時升級數據庫並不是解決方案。

+1

你是在開玩笑。 MySQL在這個時代仍然不支持Unicode?這是不合情理的。當你只能處理1,2或3字節的UTF-8序列時,假裝你支持Unicode,這與說你在僅支持1字節的ASCII序列時支持Unicode一樣重要。要麼您支持任何合法的Unicode代碼點,要麼您不支持Unicode。這是一個二元的東西。聽起來像MySQL不支持Unicode。請告訴我這是一個笑話。 – tchrist 2012-02-15 22:03:27

+2

@tchrist:MySQL 5.5.3及更高版本通過新的「utf8mb4」「字符集」(http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html)支持正確的UTF-8。 。但是,「utf8」「字符集」僅支持最多3個字節的UTF-8多字節字符,據報道可防止不同MySQL版本之間的複製問題。在未來的MySQL版本中,「utf8」可能會變成「utf8mb4」的別名。 – ninjalj 2012-02-18 09:26:57

+0

類似於[這個問題](http://stackoverflow.com/questions/8491431/remove-4-byte-characters-from-a-utf-8-string)除了它要求在PHP而不是Java的解決方案。 – 2016-08-05 15:27:51

回答

10

我們最終在Java中爲這個問題實現了以下方法。 Basicaly用更高的代碼點替換字符,然後替換最後3字節的UTF-8字符。

偏移量計算是爲了確保我們保持在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

謝謝。我用這個來避免轉換我的整個MySQL字符集。我的數據中不需要外星人角色或便便角色。 – Robert 2017-01-04 00:26:42

2

5字節utf-8序列以111110xx-字節開頭,6字節utf-8序列以1111110x-字節開頭。需要注意的是,沒有1-4字節的utf-8序列的後續字節包含較大的字節,因爲後續字節始終爲10xxxxxx格式。

因此,你可以通過字節,每次你看到一個字節的類型111110xx然後只發出'?'到輸出流/數組,同時跳過輸入中的下4個字節;模擬6字節序列。

+2

無論如何,5字節和6字節的序列在UTF-8中無效 - 這並不是說它們不能出現在源文本中。 – 2012-02-13 12:59:18

+0

最好是安全的 – 2012-02-13 13:07:24

+0

如果5字節和6字節的序列不合法,它們(應該)不會成爲問題。我的問題是目前有4byte序列是合法的,但mysql支持mysql。 – pvgoddijn 2012-02-14 12:06:15

4

另一個簡單的解決方案是使用正則表達式[^\u0000-\uFFFF]。例如在java中:

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

謝謝,優秀的答案 – tjeubaoit 2017-01-23 07:02:10