当前位置: 首页 > 面试题库 >

有效的Unicode字符串可以包含FFFF吗?Java / CharacterIterator是否损坏?

顾嘉纳
2023-03-14
问题内容

以下是java.text.CharacterIterator文档摘录:

* 这interface定义了用于文本上双向迭代的协议。迭代器遍历有界字符序列。[…]方法previous()next()用于迭代。DONE如果它们返回,则表明迭代器已到达序列的末尾。

  • static final char DONE:迭代器到达文本的结尾或开头时返回的常量。该值是\uFFFF“非字符”值
    ,该不应出现在任何有效的Unicode字符串中

斜体部分是我难以理解的部分,因为从我的测试来看,它看起来很像Java
String可以包含\uFFFF,并且似乎没有任何问题,除了明显的规定的CharacterIterator遍历惯用法会中断是因为误报(例如,在未真正“完成”时next()返回'\uFFFF' == DONE)。

以下是说明“问题”的代码段(另请参见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一个IllegalArgumentException如果事实上\uFFFF在有效Unicode字符串是被禁止的?
  • 有效的Unicode字符串实际上不应包含\uFFFF吗?
  • 如果这是真的,那么Java的“坏”由违反Unicode规范(对于大部分),允许String含有\uFFFF呢?

问题答案:

编辑(2013-12-17):
彼得·O。在下面提出了一个很重要的观点,这使这个答案是错误的。下面的旧答案用于历史准确性。

回答您的问题:

所规定的遍历惯用法是否由于“ uFFFF”的错误假设而被“破坏”了?

否。U+
FFFF是所谓的非字符。根据Unicode标准的16.7节:

非字符是Unicode标准中永久保留供内部使用的代码点。禁止在Unicode文本数据的开放式交换中使用它们。

Unicode标准预留了66个非字符代码点。每个平面的最后两个代码点是非字符:在BMP上为U + FFFE和U + FFFF,在平面1上为U +
1FFFE和U + 1FFFF,依此类推,在平面16上最多为U + 10FFFE和U +
10FFFF。总共34个代码点。此外,BMP中还有另外32个非字符代码点的连续范围:U + FDD0..U + FDEF。

### StringCharacterIterator实现是否“中断”了,因为如果实际上在有效的Unicode字符串中禁止了\
uFFFF,它不会抛出IllegalArgumentException?

不完全的。允许应用程序以他们想要的任何方式在 内部 使用这些代码点。再次引用标准:

应用程序可以在内部自由使用这些非字符代码点中的任何一个,但 决不要
尝试交换它们。如果在开放交换中接收到非字符,则无需应用程序以任何方式对其进行解释。但是,优良作法是将其识别为非字符并采取适当的措施,例如用U +
FFFD REPLACEMENT
CHARACTER替换它,以在文本中指出问题。不建议仅从此类文本中删除非字符代码点,因为删除未解释的字符会导致潜在的安全问题。

因此,尽管您永远都不会遇到来自用户,其他应用程序或文件的此类字符串,但如果知道自己在做什么,则可以将其放入Java字符串中(这基本上意味着您无法在该字符串上使用CharacterIterator,虽然。

有效的Unicode字符串实际上不应包含\ uFFFF吗?

如上所述,用于交换的任何字符串都 不得 包含它们。在您的应用程序中,您可以随意使用它们所需的任何方式。

当然,Java char只是一个16位无符号整数,并不真正在乎它所拥有的值。

如果是真的,那么Java是否“破坏了”(通过大多数情况下)通过允许String包含\ uFFFF来违反Unicode规范?

否。实际上,关于非字符的部分甚至建议使用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的情况下。



 类似资料:
  • 问题内容: 我正在编写一个程序,其中用户以以下格式输入字符串: 我需要检查字符串中是否有数字 然后只提取数字。 如果我使用或,则无论输入的内容是什么,程序都无法在字符串中找到数字,但是仅在只有数字的情况下才能使用。 我可以使用什么作为查找和提取的解决方案? 问题答案: 我使用的解决方案如下所示: 我确信这不是一个完美的解决方案,但它满足了我的需求。谢谢大家的帮助。:)

  • 问题内容: 如何检查字符串是否包含\ n或换行符? 问题答案: 如果字符串是在同一程序中构造的,则建议使用以下命令: 但是,如果您指定使用\ n,则此驱动程序说明了如何做: 导致 回应您的评论: 结果是

  • 我能够通过使用下面这个问题的注释提供的代码来解决这个问题。所有其他帖子都是有效的! 我使用的有用的东西来自第一个评论。虽然提供的所有示例代码似乎也是有效的!

  • 问题内容: base64编码的字符串是否可能包含空格?具体来说,它可以在字符串 末尾 包含空格吗? PS。我正在考虑整个“ MySQL在将字符串存储在VARCHAR字段中时会修剪尾随空白” ;-) 问题答案: 不,它不能。见Base64编码通过使用允许的字符库,这是人物,,,和(最后两个可能因实施不同),以及填充字符(不过这也取决于实现一些实现不使用填充在所有)。

  • 问题内容: 我在寻找Python中的方法。 我想要做: 问题答案: 你可以使用in运算符: