如何建立编码字符的代码点?

时间:2013-01-08 19:20:48

标签: java unicode codepoint

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

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

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

char(隐含地)是UTF-16BE编码中的16位代码单元。此编码可以表示具有单个char的基本多语言平面字符。 supplementary range使用两个 - char序列表示。

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

当您从isHighSurrogate传入两个连续值时,需要两个char的代码点将满足isLowSurrogatesequencecodePointAt方法可用于从代码单元序列中提取代码点。从代码点到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(); }
}