バイト ストリーム (文字を表す) とストリームのエンコーディングが与えられた場合、文字のコード ポイントを取得するにはどうすればよいでしょうか?
InputStreamReader r = new InputStreamReader(bla, Charset.forName("UTF-8"));
int whatIsThis = r.read();
上記のスニペットで read() によって返されるものは何ですか? それはユニコードのコードポイントですか?
Reader.read()
キャスト可能な値を返しchar
ます。使用可能なデータがなくなった場合は-1を返します。
Achar
は、(暗黙的に)UTF-16BEエンコーディングの16ビットコードユニットです。このエンコーディングは、単一ので基本的な多言語面の文字を表すことができchar
ます。補足範囲は、2つのchar
シーケンスを使用して表されます。
このCharacter
型には、UTF-16コード単位をUnicodeコードポイントに変換するためのメソッドが含まれています。
char
2つのsを必要とするコードポイントは、シーケンスから2つの連続した値を渡すときに、 isHighSurrogateとisLowSurrogateを満たします。codePointAtメソッドを使用して、コードユニットシーケンスからコードポイントを抽出できます。コードポイントから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(); }
}
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