使用charAt方法进行字符串反转时可能出现的问题

时间:2016-03-14 13:25:14

标签: java string charat

我看到评论herecharAt的所有解决方案都是错误的。我无法完全理解并在互联网上找到关于charAt的内容。当我查看源代码时,它只返回char数组中的一个元素。所以我的问题是,如果使用charAt有任何问题或问题吗?

评论就是那样

  

严格地说,基于charAt的所有解决方案都是错误的   charAt不会给你“the at at”,而是“code unit at”,   并且有代码单元不是字符和字符   需要多个代码单元。

8 个答案:

答案 0 :(得分:14)

使用不同的字节数编码不同的字符(使用UTF-16方案)。例如,“A”字符表示如下:

01000001

到目前为止一切顺利。

但如果你有像这样的角色,你就会遇到问题。其UTF-16表示(BE)是:

11011000 00110101 11011101 00110100

然后charAt确实可以返回该角色的第二个代码单元。

参见String#charAt的JDK 7实现:

public char charAt(int index) {
    if ((index < 0) || (index >= count)) {
        throw new StringIndexOutOfBoundsException(index);
    }
    return value[index + offset];
}

答案 1 :(得分:11)

在Java中,String本质上是char的数组。同样,char是UCS-2(UTF-16)代码点。

这有两个问题:

  1. 并非所有字符都可以用UTF-16中的单个代码点表示。
  2. Unicode支持combining characters
  3. 重新排序属于这两种情况之一的字符会导致String不正确。

    StringBuilder's reverse考虑​​了第一种情况,但我不知道任何考虑到第二种情况的内容。

答案 2 :(得分:6)

上面说的是真的,一些代码单元需要表示两个字符。由于Java使用16位字符,因此很少遇到;但严格来说,任何使用charAt(...)而不考虑被访问的char是否是两个char代码单元的一部分的代码都会暴露给字符处理问题。

要测试您是否使用两个字符代码单元,您应该检查charAt(...)的初始值是否在0xD8000xDFFF的范围内;因为该范围表示两个字符代码单元的开始。

答案 3 :(得分:6)

正如其他答案所指出的那样,某些字符可能会占用多个代码单元,如果您尝试单独解释这些代码单元中的任何一个,或者与其他代码单元结合使用,您将获得无效字符。

要记住的另一件事是,在字符串中使用2代码单元字符会将所有后续索引移动1,例如第十个字符将是charAt(10)而不是charAt(9) - 因此,即使您没有遇到字符本身的编码问题,您也会发现自己在字符串中稍后通过索引提取错误的字符。 / p>

答案 4 :(得分:5)

严格来说,是的,存在问题,正如您强调的原因所述。问题是某些角色可能需要多于1 char来表示。因此,通过使用String.charAt,当你反转字符串时,你会有一个新的半随机字符,因为按照构成该字符的两个字符的顺序切换。

但同样,这是严格来说

答案 5 :(得分:5)

关于文本有许多常见的致命破坏假设,特别是如果你离开“只有一个西方国家”的利基,你在使用unicode时就会这样做。
只是在处理UTF-16时专门开始一些相关的要点:

  • 代码点可能是多个代码单元。
  • 字符可能是多个代码点。
  • 代码点可能是多个字符。

反转文本时的其他相关性是LTR和RTL覆盖,需要特殊处理。

我建议您阅读Why does modern Perl avoid UTF-8 by default?的已接受答案,特别是假设破解部分,该部分与编程语言无关。

答案 6 :(得分:3)

String.charAt方法 是安全的(对于某些“安全”的定义),但如果您的字符串包含Basic Multilingual Plane以外的字符,则可以使用它,而不安全代码点的范围为0到65535。

您可以使用String.charAt实现字符串撤消 - AbstractStringBuilder直接使用char[],但这在逻辑上与使用String.charAt()相同。它基本上实现了两个过程:

  • 第一个反转字符,但也检查任何代理对
  • 第二次重新推翻代理对。

答案 7 :(得分:2)

您问题最简单的例子是UTF-8字符,例如ñ..

charAt()将轻松返回ASCII字符,因为ASCII字符占用1个字节。另一方面,UTF-8 / UTF-16字符可能占用多个字节,因此您可能会收到意外的输出。

许多语言都有UTF-8格式的字母/符号,所以假设您的应用程序提供了某些特定于语言环境的信息,您可能会使用utf-8字符,而charAt()在这种情况下会失败。