如何迭代 Java 字符串的 unicode 代码点?

所以我知道 String#codePointAt(int),但是它是由 char偏移量索引的,而不是由代码点偏移量索引的。

我想试试这样的方法:

但我担心的是

  • 我不确定在高代理范围内自然存在的代码点是以两个 char值还是一个值存储
  • 这似乎是一个非常昂贵的方法来遍历字符
  • someone must have come up with something better.
35744 次浏览

是的,Java 使用 UTF-16-esque 编码来表示字符串的内部表示形式,而且,是的,它使用代理机制对基本多语言平面(BMP)之外的字符进行编码。

如果你知道你要处理的是 BMP 之外的字符,那么这里有一个规范的方法来遍历 Java 字符串的字符:

final int length = s.length();
for (int offset = 0; offset < length; ) {
final int codepoint = s.codePointAt(offset);


// do something with the codepoint


offset += Character.charCount(codepoint);
}

Iterating over code points is filed as a feature request at Sun.

参见 漏洞报告

还有一个关于如何迭代字符串代码点的示例。

我想添加一个可以处理 foreach 循环(裁判)的变通方法,另外,当你移动到 java 8时,你可以很容易地将它转换成 java 8的新 字符串 # codePoint方法:

你可以这样用 foreach:

 for(int codePoint : codePoints(myString)) {
....
}

方法如下:

public static Iterable<Integer> codePoints(final String string) {
return new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int nextIndex = 0;
public boolean hasNext() {
return nextIndex < string.length();
}
public Integer next() {
int result = string.codePointAt(nextIndex);
nextIndex += Character.charCount(result);
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}

或者,如果您只想将一个字符串转换为一个 int 代码点数组(如果您的代码可以更容易地使用一个 int 代码点数组)(可能比上面的方法使用更多的 RAM) :

 public static List<Integer> stringToCodePoints(String in) {
if( in == null)
throw new NullPointerException("got null");
List<Integer> out = new ArrayList<Integer>();
final int length = in.length();
for (int offset = 0; offset < length; ) {
final int codepoint = in.codePointAt(offset);
out.add(codepoint);
offset += Character.charCount(codepoint);
}
return out;
}

值得庆幸的是,使用“ codePointAt”可以安全地处理 UTF-16(Java 的内部字符串表示)的代理对性。

Java8添加了返回包含代码点的 IntStreamCharSequence#codePoints。 You can use the stream directly to iterate over them:

string.codePoints().forEach(c -> ...);

或者使用 for 循环将流收集到一个数组中:

for(int c : string.codePoints().toArray()){
...
}

这些方法可能比 Jonathan Feinbergs 的解决方案更昂贵,但它们的读/写速度更快,而且性能差异通常不大。