2013-07-08 159 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