我怎样才能遍历Javastring的unicode代码点?

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

我正在考虑尝试如下所示:

  • 使用String#charAt(int)来获取索引处的char
  • testingchar是否在高代理范围内
    • 如果是的话,使用String#codePointAt(int)来获取代码点,然后将索引值加2
    • 如果不是,则使用给定的char值作为代码点,并将索引值加1

但是我的担心是

  • 我不确定自然处于高代理范围内的代码点是否将被存储为两个char值或一个
  • 这似乎是一个非常昂贵的方式来遍历字符
  • 有人一定会想出更好的东西。

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

如果你知道你将要处理BMP以外的字符,那么这里是迭代Javastring的规范方法:

 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); } 

Java 8添加了CharSequence#codePoints ,它返回一个包含代码点的IntStream 。 您可以直接使用该stream来遍历它们:

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

或者通过将stream收集到一个数组中来进行for循环:

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

这些方法可能比Jonathan Feinbergs的解决scheme更昂贵,但是它们的读/写速度更快,性能差异通常是微不足道的。

迭代代码点是在Sun提交的function请求。

参见Sun Bug Entry

这里还有一个关于如何迭代String CodePoints的例子。

以为我会添加一个解决方法,与foreach循环( ref ),加上你可以转换到Java 8的新的String#codePoints方法,当你移动到Java 8:

 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(); } }; } }; } 

那么你可以像这样使用foreach:

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

或者,如果你只是想把一个string转换为一个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; }