2013-07-08 157 views
6

我試圖找到一個子字符串方法或characterAt在字符串中包含UTF-8編碼的文本在JAVA中的方法。字符串或characterAt UTF8字符串與2個字節的字符在JAVA

JAVA在內部使用UTF-16。這意味着一個String由大小爲2個字節的字符組成。 UTF-8字符的大小最多可達6個字節。當JAVA將它存儲在一個String中時,它將UTF-8字符分成多個字符。

例如: 字符U + 20000(UTF-8十六進制:F0 A0 80 80)在內部存儲在JAVA爲具有兩個字符(UTF-16十六進制:D840和DC00)的字符串。

如果您有包含4字節UTF-8字符並使用長度的字符串,則答案爲「2」。當你使用子字符串(0,1)時,你會得到字符的前半部分。

一些代碼來說明這一點:

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); 

所有這一切,即使出現意外,是不是一個錯誤,因爲JAVA工作在UTF-16。 固有的UTF-8支持會很好。但它不在那裏。

JAVA是否有默認庫中的任何類,或者某個類是否存在某個提供UTF-8支持的地方?如:

  • utf8string.length() - 返回1,如果有在
    有一個4字節字符
  • utf8string.getCharacterAt(0) - 返回的第一個字符, 不是它的前半部分。
  • utf8string.substring(0,1) - 返回 第一個字符,而不是前半部分。

或者,這是什麼常用的解決方案?在讀取UTF-8文件時,將所有非UTF-16支持的UTF-8字符轉換爲默認的UTF-16字符?結果,失去了UTF-16不支持的代碼範圍內的所有字符信息?這在我的具體實施中不一定是個問題,所以如果有這樣一種常見的方式,我會很感興趣。

回答

7

JAVA在默認庫中是否有任何類,或者某個類是否存在某個提供UTF-8支持的地方?

你不是真的在UTF-8支持之後。您在Unicode代碼點(普通的32位整數)之後,而不是UTF-16代碼單元。是的,Java爲此提供了支持,但它不是,很容易與合作。

例如,要獲得特定的代碼點,請記住您提供的索引是以UTF-16代碼單位表示,而不是代碼點。

要找到代碼點的長度,請使用String.codePointCount

要查找子字符串,您需要按照UTF-16代碼單位查找偏移量,然後使用正常的substring方法;使用String.offsetByCodePoints找到正確的索引。

基本上通過String API查看包含codePoint的所有方法。

+0

謝謝,這回答了我的問題的第一部分。 對於第二部分,我使用了http://stackoverflow.com/questions/12867000/how-to-remove-surrogate-characters-in-java。因爲我不想讓這些代碼點中的字符使我的字符串操作複雜化。 – Wouter

+0

另外,對於可能需要所有代碼點的其他人來說,查看下面的內容可能會很有趣:http://avro.apache.org/docs/1.6.1/api/java/org/apache/avro /util/Utf8.html – Wouter

+0

那麼,這是用於子字符串? public static String substringUtf8(String utf8String,int from,int to){ return utf8String.substring(utf8String.offsetByCodePoints(0,from),utf8String.offsetByCodePoints(0,to));} – RobertG

0

您應該尋找的是Java對UTF-32的原生支持。檢查出String#*codePoint*方法,如codePointAt