【发布时间】:2011-11-20 13:12:16
【问题描述】:
假设我们想要恢复以下字符串“áe”。
它的 unicode 是“\u0061\u0301\u0065”。
还原它的幼稚方法是逐个字符
private static String reverseStringNaive(String s) {
char[] characters = new char[s.length()];
for (int i = s.length() - 1; i >= 0; i--) {
int j = s.length() - i - 1;
characters[j] = s.charAt(i);
}
return new String(characters);
}
当我们希望得到“eá”(\u0065\u0061\u0301)时,这给了我们“éa”(\u0065\u0301\u0061)。重音“´”应该和“a”连在一起,而不是变成“e”。
以下代码为我提供了该字符串的预期结果:
private static String reverseString(String s) {
char[] characters = new char[s.length()];
for (int i = s.length() - 1; i >= 0; i--) {
int j = s.length() - i - 1;
if (Character.isLetterOrDigit(s.charAt(i)) || Character.isISOControl(s.charAt(i))) {
characters[j] = s.charAt(i);
} else {
characters[j] = s.charAt(i-1);
characters[j+1] = s.charAt(i);
i--;
}
}
return new String(characters);
}
我正在检查每个字符是字母、数字还是 ISO 控制。如果不是,我假设它应该与前一个字符粘在一起。
问题是,我还应该检查或担心其他事情吗?我的做法还幼稚吗?
【问题讨论】:
-
为什么有人想这样做? :-)
-
是否可以容忍规范化形式的变化?
-
您绝不能使用
charAt。它坏了。 你只是非法颠倒了你所有的代理人!!! -
@pablosaraiva 您必须通过字形边界,而不是代码点边界,当然也不是代码单元边界来遍历它。看起来
icu.text.BreakIterator.getCharacterInstance可以用来构建一些东西,但我没有尝试过。在 Perl 中,它支持扩展的字素集群要容易得多:只需reverse /(\X)/g。如果你不这样做,你还可以反转 CRLF 组合,足够的错误。