以下摘自java.text.CharacterIterator
文档:
此
interface
定义了对文本进行双向迭代的协议。迭代器迭代有界字符序列。 [...]方法previous()
和next()
用于迭代。如果[...]则返回DONE
,表示迭代器已到达序列的末尾。
static final char DONE
:当迭代器到达文本的结尾或开头时返回的常量。值为\uFFFF
,“非字符”值不应出现在任何有效的Unicode字符串中。
斜体部分是我无法理解的部分,因为从我的测试来看,它看起来像Java String
肯定包含\uFFFF
,并且似乎没有任何问题有了它,除了明显有规定的CharacterIterator
遍历习语由于误报而中断(例如next()
当它没有真正“完成”时返回'\uFFFF' == DONE
。)
这是一个片段来说明“问题”(see also on ideone.com):
import java.text.*;
public class CharacterIteratorTest {
// this is the prescribed traversal idiom from the documentation
public static void traverseForward(CharacterIterator iter) {
for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
System.out.print(c);
}
}
public static void main(String[] args) {
String s = "abc\uFFFFdef";
System.out.println(s);
// abc?def
System.out.println(s.indexOf('\uFFFF'));
// 3
traverseForward(new StringCharacterIterator(s));
// abc
}
}
那么这里发生了什么?
\uFFFF
做出了错误的假设?StringCharacterIterator
实施是否“已损坏”,因为它没有例如如果实际throw
在有效的Unicode字符串中被禁止,则IllegalArgumentException
\uFFFF
\uFFFF
?String
包含\uFFFF
?答案 0 :(得分:27)
编辑(2013-12-17): Peter O.在下面提出了一个很好的观点,这使得这个答案错了。以下旧答案,历史准确性。
回答你的问题:
没有。 U + FFFF是所谓的非角色。来自Section 16.7 of the Unicode Standard:
非字符是Unicode标准中永久保留供内部使用的代码点。禁止在开放式交换Unicode文本数据时使用它们。
...
Unicode标准预留了66个非字符代码点。最后两个代码点 每个平面都是非特征的:BMP上的U + FFFE和U + FFFF,U + 1FFFE和U + 1FFFF 在平面1上,依此类推,在平面16上最多为U + 10FFFE和U + 10FFFF,共34个代码 点。此外,还有另外32个非字符代码点的连续范围 BMP:U + FDD0..U + FDEF。
不完全。允许应用程序以他们想要的任何方式在内部内部使用这些代码点。再次引用标准:
应用程序可以在内部自由使用任何这些非字符代码点,但应该 从不尝试交换它们。如果在开放式交换中收到非特征,则a 申请不需要以任何方式解释。但是,将它识别为非字符并采取适当的操作(例如用U + FFFD REPLACEMENT CHARACTER替换它)来表示文本中的问题是一种很好的做法。不建议这样做 由于潜在的安全性,只需从此类文本中删除非字符代码点 删除未解释的字符所导致的问题。
因此,虽然您不应该从用户,另一个应用程序或文件中遇到这样的字符串,但如果您知道自己在做什么,则可以将其放入Java字符串中(这基本上意味着您无法使用CharacterIterator)但是,那个字符串。
如上所述,用于交换的任何字符串都不得包含它们。在您的应用程序中,您可以随意使用它们。
当然,Java char
只是一个16位无符号整数,并不关心它所拥有的值。
没有。实际上,关于非字符的部分甚至建议使用U + FFFF作为哨兵值:
实际上,非字符可以被认为是应用程序内部的私有代码点。 与第16.5节“私有使用字符”中讨论的私有字符不同 分配字符,用于开放式交换,受制于 私人协议解释,非人格永久保留(未分配) 并且在他们可能的应用程序之外没有任何解释 - 内部私有 使用
U + FFFF和U + 10FFFF。这两个非特征代码点具有存在的属性 与特定Unicode编码形式的最大代码单元值相关联。在 UTF-16,U + FFFF与最大的16位代码单元值FFFF 16 相关联。 U + 10FFFF是 与最大合法的UTF-32 32位代码单元值相关联,10FFFF 16 。这个属性 将这两个非字符代码点用作内部目的作为哨兵。对于 例如,它们可能用于指示列表的结尾,以表示索引中的值 保证高于任何有效的字符值,依此类推。
CharacterIterator遵循这一点,因为当没有更多字符可用时它返回U + FFFF。当然,这意味着如果您在应用程序中对该代码点有另一种用途,您可以考虑使用不同的非字符用于此目的,因为已经采用了U + FFFF - 至少如果您使用的是CharacterIterator。
答案 1 :(得分:18)
其中一些答案在此期间发生了变化。
Unicode联盟最近发布了Corrigendum 9,澄清了这一角色 Unicode字符串中的非字符,包括U + FFFF。它指出虽然非人物是为了 在内部使用,他们可以在Unicode字符串中合法发生。
这意味着语句“值为\ uFFFF,'不是字符'值,不应出现在任何有效的Unicode字符串中。”就是现在 不正确,因为U + FFFF 可以出现在有效的Unicode字符串中。
因此:
java.lang.String
的规范说“字符串代表
UTF-16格式的字符串。“U + FFFF在Unicode字符串中是合法的,因此Java不违反Unicode
允许在包含它的字符串中使用U + FFFF。答案 2 :(得分:3)
StringCharacterIterator实现是否“已损坏”,因为它没有例如如果实际上在有效的Unicode字符串中禁止使用\ uFFFF,则抛出IllegalArgumentException?
不严格按照Unicode,但它与Java的其他字符串处理接口不一致,并且这种不一致可能会产生非常不愉快的影响。想想我们从字符串处理中获得的所有安全漏洞,而不是将\0
视为终结符。
我会强烈避免使用CharacterIterator
界面。
答案 3 :(得分:2)
是的,CharacterIterator使用0xFFFF作为DONE值有点异常。但从有效的文本处理角度来看,这一切都是有道理的。
String类不禁止0xFFFF“非字符”以及其他保留或未映射的Unicode代码点。为此,需要String构造函数检查每个提供的char
值。它还会出现处理包含将来(相对于JVM)Unicode版本定义的Unicode代码点的文本的问题。
另一方面,CharacterIterator接口旨在通过调用一个just方法来允许迭代;即next()
。他们决定使用一个显着的char
值来表示“不再”,因为其他选择是:
int
作为返回类型,对于调用者来说生活更复杂。如果CharacterIterator用于“真正的”Unicode文本,那么您不能包含0xFFFF的事实不是问题。有效的Unicode文本不包含此代码点。 (实际上,将0xFFFF保留为非字符的原因是支持将Unicode文本表示为以非字符值终止的字符串的应用程序。使用0xFFFF作为字符会完全破坏该字符。)
底线是:
String
和