Mar*_*oun 14
不同的字符用不同的字节数编码(使用UTF-16方案).例如,"A"字符表示如下:
01000001
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.
但如果你有一个喜欢的角色 ,你会遇到问题.它的UTF-16表示(BE)是:
11011000 00110101 11011101 00110100
Run Code Online (Sandbox Code Playgroud)
然后charAt
确实可以返回该角色的第二个代码单元.
请参阅JDK 7实现String#charAt
:
public char charAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index + offset];
}
Run Code Online (Sandbox Code Playgroud)
Pow*_*ord 11
在Java中,String
本质上是一个数组char
.同样,a char
是UCS-2(UTF-16)代码点.
这有两个问题:
重新排序属于这两种情况之一的字符将导致String
不正确.
StringBuilder
反过来考虑了第一种情况,但我不知道任何考虑到第二种情况的事情.
上面说的是真的,一些代码单元需要表示两个字符.由于Java使用16位字符,因此很少遇到; 但严格来说,任何使用charAt(...)而不考虑被访问的char是否是两个char代码单元的一部分的代码都会暴露给字符处理问题.
为了测试,如果您使用的是两个char代码单元工作时,应检查是否从初始值charAt(...)
的范围是从0xD800
到0xDFFF
; 因为该范围表示两个字符代码单元的开始.
正如其他答案所指出的,某些字符可以占用多个代码单元,如果您尝试单独解释这些代码单元中的任何一个,或者与其他代码单元组合,您将获得无效字符.
另外要记住的是,在字符串中使用2个代码单元字符会将所有后续索引移动一个,因此例如第十个字符将charAt(10)
代替charAt(9)
- 所以即使您没有受到编码问题的影响对于角色本身,您可能会发现自己后来在字符串中通过索引提取错误的字符.
严格地说,是的,存在问题,正如您强调的原因所述.问题是某些字符可能需要多于1 char
才能表示.因此,通过使用String.charAt,当你反转字符串时,你将有一个新的半随机字符,因为按照构成该字符的两个字符的顺序切换.
但同样,这是严格来说
关于文本有许多常见的致命破坏假设,特别是如果你离开"只是一个西方国家"的利基,你在使用unicode时就会这样做.
只是在处理UTF-16时专门提出一些相关要点:
反转文本时的另外相关性是LTR和RTL覆盖,这需要特殊处理.
我建议你阅读接受的答案为什么现代Perl默认避免使用UTF-8?,特别是该部分假定破碎,该部分是编程语言不可知的.
归档时间: |
|
查看次数: |
1362 次 |
最近记录: |