1

Java 文字を xml エンティティに変換するには、文字列内の各文字に対して次の操作を実行できます。

buf.append("&#x"+ Integer.toHexString(c | 0x10000).substring(1) +";");

ただし、他のスタックオーバーフローの質問によると、これは Unicode 3.0 でのみ機能します。

UTF-8 リーダーを使用して文字列を読み取る場合、文字列には Unicode 6.0 で動作する形式の文字が含まれていると考えられます (javadoc に従って Java 7 が Unicode 6.0 をサポートしているため)。

その文字列を取得したら、どうすればそれを xml エンティティとして書き出すことができますか? 理想的には、Unicode の新しいバージョンが出てきても引き続き機能する API を使用します。

4

2 に答える 2

4

正しい用語を使用していないか、ここで多くの混乱が生じています。

文字参照表記は&#x数値コードポイントを指定するだけです。リーダーやパーサーが使用する Unicode のバージョンとは無関係です。

コードは、文字の数値が 2 16未満であると想定しているため、実際には Unicode 1.x とのみ互換性があります。Unicode 2.0 の時点では、これは正しい仮定ではありません。一部の文字は単一の Javacharで表されますが、他の文字は 2 つの Java で表されます(サロゲートcharと呼ばれます)。

「UTF-8リーダー」が何であるかわかりません。Readerは値を読み取るだけで、UTF-8 エンコーディング (または特定の CharsetDecoder が使用するエンコーディング) を使用してバイトを文字に変換するためにCharsetDecoderを使用するInputStreamReadercharを除いて、UTF-8 またはその他の文字セットについては知りません。

いずれにせよ、Reader は XML&#x文字参照表記を解析しません。そのためには、XML パーサーを使用する必要があります。

Reader または XML パーサーは、Java が認識している Unicode バージョンの影響を受けません。これは、どのような方法でも、Unicode データベースを参照する Reader または XML パーサーがないためです。文字は解析時に数値として扱われます。それらが任意の Unicode バージョンで割り当てられたコードポイントに対応するかどうかは考慮されません。

最後に、 String を XML として書き出すには、Formatterを使用できます。

static String toXML(String s) {
    Formatter formatter = new Formatter();
    int len = s.length();
    for (int i = 0; i < len; i = s.offsetByCodePoints(i, 1)) {
        int c = s.codePointAt(i);
        if (c < 32 || c > 126 || c == '&' || c == '<' || c == '>') {
            formatter.format("&#x%x;", c);
        } else {
            formatter.format("%c", c);
        }
    }
    return formatter.toString();
}

ご覧のとおり、文字は単なる数値であるため、Unicode バージョンに依存するコードはありません。各数値が割り当てられた Unicode コードポイントであるかどうかは関係ありません。

(私の最初の傾向は XMLStreamWriter クラスを使用することでしたが、Java 1.8 の時点で、ISO-8859-1 や US-ASCII などの非 Unicode エンコーディングを使用する XMLStreamWriter は、サロゲート ペアを単一文字エンティティとして適切に出力しないことが判明しました。 .0_05.)

于 2014-07-01T03:00:17.347 に答える
2

当初、Java はchar型を 16 ビット長にすることで Unicode 1.0 をサポートしていましたが、Unicode 2.0 では、16 ビットで許可されている数よりも多くの文字をサポートするサロゲート文字メカニズムが導入されたため、Java 文字列は UTF-16 でエンコードされました。つまり、一部の文字は表すために 2 つの Java 文字が必要であり、それらは高サロゲート文字と低サロゲート文字と呼ばれます。

String内のどの文字が実際に高い/低いサロゲート ペアであるかを知るには、次のユーティリティ メソッドを使用できますCharacter

Character.isHighSurrogate(myChar); // returns true if myChar is a high surrogate
Character.isLowSurrogate(myChar); // same for low surrogate

Character.isSurrogate(myChar); // just to know if myChar is a surrogate

サロゲートの上位または下位の文字がわかったら、次の方法で各ペアを Unicode コードポイントに変換する必要があります。

int codePoint = Character.toCodePoint(highSurrogate, lowSurrogate);

コードは千の言葉に値するため、これは、文字列内の us-ascii 文字以外の xml 文字参照に置き換えるメソッドの例です。

public static String replaceToCharEntities(String str) {
    StringBuilder result = new StringBuilder(str.length());

    char surrogate = 0;
    for(char c: str.toCharArray()) {

        // if char is a high surrogate, keep it to match it
        // against the next char (low surrogate)
        if(Character.isHighSurrogate(c)) {
            surrogate = c;
            continue;
        }

        // get codePoint
        int codePoint;
        if(surrogate != 0) {
            codePoint = Character.toCodePoint(surrogate, c);
            surrogate = 0;
        } else {
            codePoint = c;
        }

        // decide wether using just a char or a character reference
        if(codePoint < 0x20 || codePoint > 0x7E || codePoint == '<'
                || codePoint == '>' || codePoint == '&' || codePoint == '"'
                || codePoint == '\'') {
            result.append(String.format("&#x%x;", codePoint));
        } else {
            result.append(c);
        }
    }

    return result.toString();
}

次の文字列の例は、16 ビット値で表すことができる非 ASCII 文字と、上位/下位のサロゲート ペアを持つ文字が含まれているため、テストに適しています。

String myString = "text with some non-US chars: 'Ñ' and ''";
于 2014-07-01T03:02:16.810 に答える