1

给定一个字节流(表示字符)和流的编码,我将如何获得字符的代码点?

InputStreamReader r = new InputStreamReader(bla, Charset.forName("UTF-8"));
int whatIsThis = r.read(); 

上面代码片段中的 read() 返回了什么?它是unicode代码点吗?

4

2 回答 2

2

它不读取 unicode 代码点,而是读取 UTF-16 代码单元。低于 0xFFFF 的代码点没有区别,但高于 0xFFFF 的代码点分别由 2 个代码单元表示。这是因为您不能在 16 位中获得高于 0xFFFF 的值。

在这种情况下也是如此:

byte[] a = {-16, -96, -128, -128}; //UTF-8 for  U+20000

ByteArrayInputStream is = new ByteArrayInputStream(a);
InputStreamReader r = new InputStreamReader(is, Charset.forName("UTF-8"));
int whatIsThis = r.read();
int whatIsThis2 = r.read();
System.out.println(whatIsThis); //55360 not a valid stand alone code point 
System.out.println(whatIsThis2); //56320 not a valid stand alone code point

使用代理值,我们将它们放在一起得到0x20000

((55360 - 0xD800) * 0x400) + (56320 - 0xDC00) + 0x10000 == 0x20000

有关 UTF-16 如何工作的更多信息:http ://en.wikipedia.org/wiki/UTF-16

于 2013-01-08T19:58:56.110 回答
2

Reader.read()char如果没有更多数据可用,则返回一个可以转换为或 -1 的值。

Achar是(隐式)UTF-16BE 编码中的 16 位代码单元。这种编码可以用单个char. 补充范围使用两个char序列表示。

Character类型包含将 UTF-16 代码单元转换为 Unicode 代码点的方法:

当您从一个序列中传入两个连续值时,需要两个chars 的代码点将满足isHighSurrogateisLowSurrogatecodePointAt方法可用于从代码单元序列中提取代码点。从代码点到 UTF-16 代码单元有类似的方法。


代码点流阅读器的示例实现:

import java.io.*;
public class CodePointReader implements Closeable {
  private final Reader charSource;
  private int codeUnit;

  public CodePointReader(Reader charSource) throws IOException {
    this.charSource = charSource;
    codeUnit = charSource.read();
  }

  public boolean hasNext() { return codeUnit != -1; }

  public int nextCodePoint() throws IOException {
    try {
      char high = (char) codeUnit;
      if (Character.isHighSurrogate(high)) {
        int next = charSource.read();
        if (next == -1) { throw new IOException("malformed character"); }
        char low = (char) next;
        if(!Character.isLowSurrogate(low)) {
          throw new IOException("malformed sequence");
        }
        return Character.toCodePoint(high, low);
      } else {
        return codeUnit;
      }
    } finally {
      codeUnit = charSource.read();
    }
  }

  public void close() throws IOException { charSource.close(); }
}
于 2013-01-08T21:05:02.227 回答