文字セットの基本:
文字セット
文字のコレクション、つまり特別なセマンティクスを持つシンボル。 「A」という文字は文字です。 「%」も文字です。これには固有の数値はなく、ASC II、Unicode、さらにはコンピューターとの直接的な関係もありません。シンボルはコンピューターが登場するずっと前から存在していました。
コード化された文字セット
数値は文字のコレクションに割り当てられます。特定の文字エンコード セットを使用して数値結果を表現できるように、文字にコードを割り当てます。他のコード化文字セットでは、同じ文字に異なる値を割り当てることができます。文字セットのマッピングは通常、USASCII、ISO 8859-1、Unicode (ISO 10646-1)、JIS X0201 などの標準化団体によって決定されます。
文字エンコード方式
エンコードされた文字セットのメンバーをオクテット (8 ビット バイト) にマッピングします。エンコード スキームは、文字エンコードのシーケンスをバイトのシーケンスとして表現する方法を定義します。文字エンコーディングの値は、エンコーディング バイトと同じである必要はなく、1 対 1 または 1 対多の関係である必要もありません。原則として、文字セットのエンコードとデコードは、オブジェクトのシリアル化と逆シリアル化として近似できます。
通常、文字データのエンコーディングはネットワーク送信やファイルの保存に使用されます。エンコード スキームは文字セットではなくマッピングですが、それらの密接な関係により、ほとんどのエンコードは別の文字セットに関連付けられます。たとえば、UTF-8、
Unicode 文字セットをエンコードするためにのみ使用されます。ただし、1 つのエンコード スキームを使用して複数の文字セットを処理することは可能です。たとえば、EUC はいくつかのアジア言語の文字をエンコードできます。
図 6-1 は、UTF-8 エンコーディング スキームを使用して Unicode 文字シーケンスをバイト シーケンスにエンコードするグラフィカル表現です。 UTF-8 は、0x80 未満の文字コード値をシングルバイト値 (標準 ASC II) にエンコードします。他のすべての Unicode 文字は、2 ~ 6 バイトのマルチバイト シーケンスとしてエンコードされます (http://www.ietf.org/rfc/rfc2279.txt)。
文字セット
charset という用語は、RFC2278 (http://ietf.org/rfc/rfc2278.txt) で定義されています。これは、エンコードされた文字セットと文字エンコード スキームのコレクションです。 java.nio.charset パッケージのクラスは Charset で、文字セット抽出をカプセル化します。
1111111111111111
Unicode は 16 ビットの文字エンコーディングです。世界中のすべての言語の文字セットを単一の包括的なマッピングに統一しようとします。これはその地位を獲得しましたが、現在では他にも多くの文字エンコーディングが広く使用されています。
ほとんどのオペレーティング システムは、I/O およびファイル ストレージの点で依然としてバイト指向であるため、Unicode またはその他のエンコーディングが使用されている場合でも、バイト シーケンスと文字セット エンコーディングの間で変換する必要があります。
java.nio.charset パッケージで構成されるクラスは、このニーズを満たします。 Java プラットフォームが文字セット エンコーディングを扱うのはこれが初めてではありませんが、最も体系的で包括的で柔軟なソリューションです。 java.nio.charset.spi パッケージは、必要に応じてエンコーダとデコーダをプラグインできるようにサーバー プロビジョニング インターフェイス (SPI) を提供します。
文字セット: デフォルト値は JVM の起動時に決定され、基礎となるオペレーティング システム環境、ロケール、JVM 構成によって異なります。特定の文字セットが必要な場合、最も安全な方法は、明示的に名前を付けることです。デフォルトのデプロイメントが開発環境と同じであると想定しないでください。キャラクタ セット名では大文字と小文字が区別されません。つまり、キャラクタ セット名を比較する場合、大文字と小文字は同じとみなされます。 Internet Assigned Names Authority (IANA) は、公式に登録されたすべての文字セット名を管理します。
例 6-1 は、さまざまな Charset 実装を使用して文字をバイト シーケンスに変換する方法を示しています。
例6-1. 標準の文字セットエンコーディングの使用
パッケージ com.ronsoft.books.nio.charset;
インポート java.nio.charset.Charset;
インポートjava.nio.ByteBuffer;
/**
* いくつかの文字列を含む同じ入力文字列を実行します。
* 非 ASCII 文字は、いくつかの Charset エンコーダを介して 16 進数をダンプします
* 結果として得られるバイト シーケンスの値。
*
* @著者 Ron Hitchens ([email protected])
*/
パブリック クラス EncodeTest {
public static void main(String[] argv) throws Exception {
// これはエンコードする文字列です
文字列入力 = "/u00bfMa/u00f1ana?";
// エンコードに使用する文字セットのリスト
String[] charsetNames = { "US-ASCII"、"ISO-8859-1"、"UTF-8"、
"UTF-16BE"、"UTF-16LE"、"UTF-16" // 、"X-ROT13"
};
for (int i = 0; i < charsetNames.length; i++) {
doEncode(Charset.forName(charsetNames[i]), input);
}
}
/**
* 指定された文字セットと入力文字列について、文字をエンコードして出力します。
* 読み取り可能な形式でバイトエンコードが行われます。
*/
private static void doEncode(Charset cs, String input) {
ByteBuffer bb = cs.encode(input);
System.out.println("文字セット: " + cs.name());
System.out.println(" 入力: " + 入力);
System.out.println("エンコード: ");
for (int i = 0; bb.hasRemaining(); i++) {
int b = bb.get();
int ival = ((int) b) & 0xff;
char c = (char) ival;
// 表の配置をきれいに保つ
if (i < 10)
System.out.print(" ");
//インデックス番号を出力する
System.out.print(" " + i + ": ");
// より良いフォーマットの出力がいつか来るでしょう...
if (ival < 16)
System.out.print("0");
// バイトの 16 進値を出力します
System.out.print(Integer.toHexString(ival));
// バイトが a の値であると思われる場合
// 印刷可能な文字、印刷する保証はありません。
// そうなる。
if (Character.isWhitespace(c) || Character.isISOControl(c)) {
System.out.println("");
} それ以外 {
System.out.println(" (" + c + ")");
}
}
System.out.println("");
}
}
文字セット: ISO-8859-1
入力:「マ?アナ?」
エンコード済み:
0:20
1: BF(?)
2:4d(M)
3:61(a)
4:f1(?)
5:61(a)
6:6e(n)
7:61(a)
8:3f(?)
文字セット: UTF-8
入力:「マ?アナ?」
エンコード済み:
0:20
1:c2(?)
2: BF(?)
3:4d(M)
4:61(a)
5:c3(?)
6: b1(±)
7:61(a)
8:6e(n)
9:61(a)
10:3f(?)
文字セット: UTF-16BE
入力:「マ?アナ?」
エンコード済み:
0:00
1:20
2:00
3: BF(?)
4:00
5:4d(M)
6:00
7:61(a)
8:00
9:f1(?)
10:00
11:61(a)
12:00
13:6e(n)
14:00
15:61(a)
16:00
17:3f(?)
文字セット: UTF-16LE
入力:「マ?アナ?」
エンコード済み:
0:20
1:00
2: BF(?)
3:00
4:4d(M)
5:00
6:61(a)
7:00
8:f1(?)
9:00
10:61(a)
11:00
12:6e(n)
13:00
14:61(a)
15:00
16:3f(?)
17:00
文字セット: UTF-16
入力:「マ?アナ?」
エンコード済み:
0:フェ(?)
1: ふ(?)
2:00
3:20
4:00
5:BF(?)
6:00
7:4d(M)
8:00
9:61(a)
10:00
11:f1(?)
12:00
13:61(a)
14:00
15:6e(n)
16:00
17:61(a)
18:00
19:3f(?)
パッケージ java.nio.charset;
パブリック抽象クラス Charset は Comparable を実装します
{
public static boolean isSupported (String charsetName)
public static Charset forName (String charsetName)
public static SortedMap availableCharsets()
パブリック最終文字列名()
public Final Set aliases()
public String 表示名()
public String displayName (ロケール locale)
パブリック最終ブール値 isRegistered()
パブリックブール値 canEncode()
パブリック抽象CharsetEncoder newEncoder();
パブリック最終 ByteBuffer エンコード (CharBuffer cb)
パブリック最終 ByteBuffer エンコード (文字列 str)
パブリック抽象CharsetDecoder newDecoder();
パブリック最終 CharBuffer デコード (ByteBuffer bb)
public abstract boolean には (Charset cs) が含まれます。
public 最終ブール値等しい (オブジェクト ob)
public Final int CompareTo (オブジェクト ob)
public Final int hashCode()
パブリック最終文字列 toString()
}
ほとんどの場合、これらのルールに注意を払うのは JVM 販売者だけです。ただし、アプリケーションの一部として独自の文字セットを使用する予定がある場合は、何をしてはいけないかを知っておくと役立ちます。 isRegistered() に対して false を返し、文字セットに「X -」で始まる名前を付ける必要があります。
文字セットの比較:
パブリック抽象クラス Charset は Comparable を実装します
{
// これは API リストの一部です
public abstract boolean には (Charset cs) が含まれます。
public 最終ブール値等しい (オブジェクト ob)
public Final int CompareTo (オブジェクト ob)
public Final int hashCode()
パブリック最終文字列 toString()
}
文字セット エンコーダ: 文字セットは、エンコードされた文字セットと関連するエンコード スキームで構成されます。 CharsetEncoder クラスと CharsetDecoder クラスは変換スキームを実装します。
CharsetEncoder API に関する注意点: まず、encode() 形式が単純であればあるほど、再割り当てされた ByteBuffer で提供する CharBuffer のエンコーディングはすべてのエンコーディングを組み合わせたものになります。これは、Charset クラスで直接 encode() を呼び出したときに呼び出される最後のメソッドです。
アンダーフロー
オーバーフロー
不正な入力
マップ不可能な文字
エンコード中に、エンコーダーが欠陥のある入力またはマップできない入力を検出した場合、結果オブジェクトが返されます。個々の文字または一連の文字をテストして、エンコードできるかどうかを判断することもできます。エンコードが可能かどうかを確認する方法は次のとおりです。
パッケージ java.nio.charset;
パブリック抽象クラス CharsetEncoder
{
// これは API リストの一部です
public boolean canEncode (char c)
public boolean canEncode (CharSequence cs)
}
報告
CharsetEncoder を作成するときのデフォルトの動作。この動作は、前述した CoderResult オブジェクトを返すことによってコーディング エラーを報告する必要があることを示します。
無視(無視)
エンコード エラーを無視し、位置がずれている場合は不正な入力を中止する必要があることを示します。
交換する
エンコーディング エラーは、エラーの入力を中止し、この CharsetEncoder に定義されている現在の置換バイト シーケンスを出力することによって処理されます。
文字セット エンコーディングは、後のデコードに備えて文字をバイトのシーケンスに変換することに注意してください。置換シーケンスを有効な文字シーケンスにデコードできない場合、エンコードされたバイト シーケンスは無効になります。
CoderResult クラス: CoderResult オブジェクトは、CharsetEncoder オブジェクトと CharsetDecoder オブジェクトによって返されます。
パッケージ java.nio.charset;
パブリック クラス CoderResult {
public static Final CoderResult オーバーフロー
public static Final CoderResult UNDERFLOW
パブリックブール値 isUnderflow()
パブリックブール値 isOverflow()
<span style="white-space:pre"> </span>public boolean isError()
public boolean isMalformed()
パブリックブール値 isUnmappable()
パブリック int length()
public static CoderResult malformedForLength (int 長)
public static CoderResult unmappableForLength (int 長)
<span style="white-space:pre"> </span>public void throwException() は CharacterCodingException をスローします
}
パッケージ java.nio.charset;
パブリック抽象クラス CharsetDecoder
{
// これは API リストの一部です
public Final CharsetDecoder リセット()
パブリック最終 CharBuffer デコード (ByteBuffer in)
CharacterCodingException をスローします
public 最終 CoderResult デコード (ByteBuffer 入力、CharBuffer 出力、
ブール値の入力の終了)
パブリック最終 CoderResult フラッシュ (CharBuffer 出力)
}
1.reset() を呼び出してデコーダをリセットし、デコーダを入力を受信できる既知の状態にします。
2. endOfInput を false に設定し、デコード エンジンにバイトを供給するために decode() を複数回呼び出したり呼び出したりしないでください。デコードが進むにつれて、指定された CharBuffer に文字が追加されます。
3. endOfInput を true に設定し、decode() を 1 回呼び出して、すべての入力が提供されたことをデコーダに通知します。
4. flash() を呼び出して、デコードされたすべての文字が出力に送信されたことを確認します。
例6-2は、キャラクタ・セット・エンコーディングを表すバイト・ストリームをエンコードする方法を示しています。
例 6-2. 文字セットのデコード
パッケージ com.ronsoft.books.nio.charset;
java.nio.* をインポートします。
java.nio.charset.* をインポートします。
java.nio.channels.* をインポートします。
java.io.* をインポートします。
/**
* 文字セットのデコードをテストします。
*
* @著者 Ron Hitchens ([email protected])
*/
パブリック クラス CharsetDecode {
/**
* 一般的なケースでの文字セットのデコードをテストし、バッファを検出して処理します
* アンダー/オーバーフロー、および入力終了時のデコーダー状態のフラッシュ。
* stdin から読み取り、ASCII エンコードされたバイト ストリームを文字にデコードします。
* デコードされた文字は stdout に書き込まれます。これは事実上 'cat' です。
* ASCII ファイルを入力しますが、単純に別の文字セット エンコーディングを使用することもできます。
* コマンドラインで指定します。
*/
public static void main(String[] argv) throws IOException {
// デフォルトの文字セットは標準 ASCII です
文字列文字セット名 = "ISO-8859-1";
// 文字セット名はコマンドラインで指定可能
if (引数の長さ > 0) {
charsetName = argv[0];
}
// チャネルを標準入力にラップし、チャネルを標準出力にラップし、
// 指定された Charset を検索し、それらを deco de メソッドに渡します。
// 指定された文字セットが無効な場合、次のタイプの例外が発生します。
// UnsupportedCharsetException がスローされます。
decodeChannel(Channels.newChannel(System.in), new OutputStreamWriter(
System.out)、Charset.forName(charsetName));
}
/**
* チャネルからバイトを読み取り、デコードする汎用静的メソッド
*彼らによると
*
* @paramソース
* EOF に読み取られる ReadableByteChannel オブジェクト
* エンコードされたバイトのソース。
* @paramライター
* デコードされた文字が書き込まれる Writer オブジェクト。
* @param 文字セット
* Charset オブジェクト。その CharsetDecoder は次の処理を行うために使用されます。
* 文字セットのデコード。Java NIO 206。
*/
public static void decodeChannel(ReadableByteChannel ソース、ライター ライター、
Charset charset) throws UnsupportedCharsetException、IOException {
// Charset からデコーダ インスタンスを取得します
CharsetDecoder デコーダ = charset.newDecoder();
// 不正な文字をデフォルトのマークに置き換えるようデコーダに指示します
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
// 根本的に異なる入力バッファ サイズと出力バッファ サイズを割り当てます。
// テスト目的のため
ByteBuffer bb = ByteBuffer.allocateDirect(16 * 1024);
CharBuffer cb = CharBuffer.allocate(57);
// バッファは空から始まり、入力が必要であることを示します。
CoderResult 結果 = CoderResult.UNDERFLOW;
ブール値 eof = false;
while (!eof) {
// 入力バッファーのアンダーフローがさらに多くの入力を必要とします。
if (結果 == CoderResult.UNDERFLOW) {
// デコーダはすべての入力を消費し、補充の準備をします
bb.clear();
// 入力バッファを埋めて EOF を監視します。
eof = (source.read(bb) == -1);
// デコーダによる読み取り用のバッファを準備します
bb.flip();
}
// 入力バイトをデコードして文字を出力し、EOF フラグを渡します。
結果 = デコーダ.デコード(bb, cb, eof);
// 出力バッファがいっぱいの場合、出力を排出します
if (result == CoderResult.OVERFLOW) {
ドレインCharBuf(cb、ライター);
}
}
// 注意して、残っている状態をデコーダからフラッシュします。
// 出力バッファのオーバーフローを検出するため
while (decoder.flush(cb) == CoderResult.OVERFLOW) {
ドレインCharBuf(cb、ライター);
}
// 出力バッファに残っている文字をすべて排出します
ドレインCharBuf(cb、ライター);
// チャネルを閉じて、バッファされたデータを標準出力にプッシュします。
ソース.close();
ライター.flush();
}
/**
* 文字バッファを排出し、その内容を指定されたバッファに書き込むヘルパー メソッド
* Writer オブジェクト。戻ると、バッファは空になり、再充填する準備ができています。
*
* @param cb
* 書き込まれる文字を含む CharBuffer。
* @paramライター
* cb 内の文字を消費するための Writer オブジェクト。
*/
static voidrainCharBuf(CharBuffer cb, Writer Writer) throws IOException {
cb.flip(); // ドレイン用のバッファを準備します
// これは CharBuffer に含まれる文字を書き込みますが、
// 実際にはバッファの状態を変更しません。
// get( ) の呼び出しによって char バッファが空になっていた場合、
// ここでループが必要になる場合があります。
if (cb.hasRemaining()) {
Writer.write(cb.toString());
}
cb.clear(); // 再度埋めるバッファを準備します。
}
}
API を参照する前に、Charset SPI がどのように機能するかを説明することが重要です。 java.nio.charset.spi パッケージには、抽出クラス CharsetProvider が 1 つだけ含まれています。このクラスの具体的な実装は、提供する Charset オブジェクトに関連する情報を提供します。カスタム文字セットを定義するには、まず java.nio.charset パッケージから Charset、CharsetEncoder、および CharsetDecoder の特定の実装を作成する必要があります。次に、それらのクラスを JVM に提供する CharsetProvider のカスタム サブクラスを作成します。
カスタム文字セットを作成します。
最低限行う必要があるのは、java.nio.charset.Charset のサブクラスを作成し、3 つの抽出メソッドの具体的な実装とコンストラクターを提供することです。 Charset クラスには、デフォルトのパラメーターなしのコンストラクターがありません。これは、パラメータを受け入れない場合でも、カスタム文字セット クラスにはコンストラクターが必要であることを意味します。これは、インスタンス化時に (コンストラクターの先頭で super() を呼び出して) Charset のコンストラクターを呼び出し、charset 仕様の名前と別名を指定する必要があるためです。これを行うと、Charset クラスのメソッドが名前関連の処理を行えるようになるため、これは良いことです。
同様に、CharsetEncoder と CharsetDecoder の具体的な実装を提供する必要があります。文字セットは、エンコードされた文字とエンコード/デコード スキームの集合であることを思い出してください。前に見たように、エンコードとデコードは API レベルでほぼ対称的です。エンコーダの実装に必要なものについて簡単に説明します。デコーダの構築にも同じことが当てはまります。
Charset と同様に、CharsetEncoder にはデフォルトのコンストラクターがないため、具象クラスのコンストラクターで super() を呼び出し、必要なパラメーターを指定する必要があります。
独自の CharsetEncoder 実装を提供するには、少なくとも具体的な encodeLoop () メソッドを提供する必要があります。単純なエンコード アルゴリズムの場合は、他のメソッドのデフォルト実装が正常に機能するはずです。 encodeLoop() は、Boolean フラグを除いて、encode() のパラメータと同様のパラメータを取ることに注意してください。 encode() メソッドは、encodeLoop() への実際のエンコーディングを表します。これは、CharBuffer パラメーターから消費される文字に注意を払うだけでよく、エンコードされたバイトを提供された ByteBuffer に出力します。
関連するエンコーダーとデコーダーを含むカスタム文字セットを実装する方法を説明したので、それらを使用してコードを実行できるように、カスタム文字セットを JVM に接続する方法を見てみましょう。
カスタム文字セットを指定します。
独自の Charset 実装を JVM ランタイム環境に提供するには、java.nio.charsets.-spi で CharsetProvider クラスの具体的なサブクラスを作成し、それぞれにパラメータのないコンストラクタを含める必要があります。 CharsetProvider クラスは構成ファイルの完全修飾名を読み取ることで特定されるため、パラメーターのないコンストラクターは重要です。このクラス名文字列は Class.newInstance() にインポートされてプロバイダーをインスタンス化します。これはパラメーターなしのコンストラクターを通じてのみ機能します。
JVM によって読み取られた構成ファイルは、java.nio.charset.spi.CharsetProvider という名前の文字セット プロバイダーを見つけます。これは、JVM クラスパスのソース ディレクトリ (META-INF/services) にあります。各 JavaArchive (JAR) には、その JAR 内のクラスとリソースに関する情報を含む META-INF ディレクトリがあります。 META-INF という名前のディレクトリを、JVM クラスパスの通常のディレクトリの先頭に配置することもできます。
CharsetProvider API はほとんど役に立ちません。カスタム文字セットを提供する実際の作業は、カスタム Charset、CharsetEncoder、および CharsetDecoder クラスの作成時に発生します。 CharsetProvider は、単に文字セットとランタイム環境の間の仲介者です。
例6-3は、キャラクタ・セットの使用法、エンコードとデコード、およびCharset SPIを示すサンプル・コードを含む、カスタムのCharsetおよびCharsetProviderの実装を示しています。例 6-3 では、カスタム Charset を実装します。
例 6-3. カスタマイズされた Rot13 文字セット
パッケージ com.ronsoft.books.nio.charset;
java.nio.CharBufferをインポートします。
インポートjava.nio.ByteBuffer;
インポート java.nio.charset.Charset;
インポート java.nio.charset.CharsetEncoder;
インポート java.nio.charset.CharsetDecoder;
インポート java.nio.charset.CoderResult;
java.util.Mapをインポートします。
java.util.Iteratorをインポートします。
java.io.Writerをインポートします。
java.io.PrintStreamをインポートします。
java.io.PrintWriterをインポートします。
インポートjava.io.OutputStreamWriter;
java.io.BufferedReaderをインポートします。
インポートjava.io.InputStreamReader;
java.io.FileReaderをインポートします。
/**
* Rot13 エンコーディングを実行する Charset 実装は、Rot-13 エンコーディングです。
* アルファベット文字を 13 ずつシフトする単純なテキスト難読化アルゴリズム
* 'a' が 'n' になる、'o' が 'b' になるなど。このアルゴリズムは普及しました
* 何年も前に Usenet ディスカッション フォーラムによって、いたずらな言葉を隠し、非表示にするために
* 質問への回答など。Rot13 アルゴリズムは対称的です。
* Rot13 によってスクランブルされたテキストにすると、オリジナルが得られます
*スクランブルされていないテキスト。
*
* この Charset エンコーディングを出力ストリームに適用すると、
* 書き出されたときに Rot13 でスクランブルされるようにそのストリームに書き込み、適用します。
* 入力ストリームに追加すると、読み取られたデータは読み取られる際に Rot13 デスクランブルされます。
*
* @著者 Ron Hitchens ([email protected])
*/
public class Rot13Charset extends Charset {
// 委任する基本文字セットエンコーディングの名前
プライベート静的最終文字列BASE_CHARSET_NAME = "UTF-8";
// 間のトランスコーディングに使用する実際の文字セットへのハンドル
// 文字とバイト これにより、Rot13 を適用できるようになります。
// マルチバイト文字セットエンコーディングへのアルゴリズム。
// ASCII アルファ文字は、基本エンコーディングに関係なく回転されます。
文字セットbaseCharset;
/**
* Rot13 文字セットのコンストラクター スーパークラス コンストラクターを呼び出します。
* 私たちが知られる名前を渡してから、への参照を保存します。
* デリゲートの文字セット。
*/
protected Rot13Charset(String canonical, String[] エイリアス) {
super(正規、エイリアス);
// 委任先の基本文字セットを保存します
BaseCharset = Charset.forName(BASE_CHARSET_NAME);
}
//------------------------------------------------ ----------
/**
* この実装を取得するために、この文字セットのユーザーによって呼び出されます。
* プライベート クラス (以下で定義) のインスタンスをインスタンス化し、それを渡します
* 基本文字セットからのエンコーダー。
*/
public CharsetEncoder newEncoder() {
return new Rot13Encoder(this,baseCharset.newEncoder());
}
/**
* この実装を取得するために、この文字セットのユーザーによって呼び出されます。
* プライベート クラス (以下で定義) のインスタンスをインスタンス化し、それを渡します
* 基本文字セットからのデコーダ。
*/
public CharsetDecoder newDecoder() {
return new Rot13Decoder(this,baseCharset.newDecoder());
}
/**
* このメソッドは具体的な文字セットで実装する必要があります。私たちは常に「ノー」と言います。
*安全です。
*/
public boolean contains(Charset cs) {
戻り値 (偽);
}
/**
* 指定されたファイル内のすべての ASCII アルファ文字を回転する共通ルーチン
* CharBuffer by 13。このコードは、upper と を明示的に比較していることに注意してください。
* メソッドを使用するのではなく、小文字の ASCII 文字を使用します
* Character.isLowerCase と Character.isUpperCase であるためです。
* 13 単位で回転するスキームは、次のアルファベット文字に対してのみ適切に機能します。
* ASCII 文字セットとそれらのメソッドは、非 ASCII Unicode に対して true を返すことができます
* 文字。
*/
プライベート void rot13(CharBuffer cb) {
for (int pos = cb.position(); pos < cb.limit(); pos++) {
char c = cb.get(pos);
文字 a = '/u0000';
// 小文字のアルファベットですか?
if ((c >= 'a') && (c <= 'z')) {
a = 'a';
}
// アルファベット大文字ですか?
if ((c >= 'A') && (c <= 'Z')) {
a = 'A';
}
// どちらかの場合は 13 ロールします
if (a != '/u0000') {
c = (char) ((((c - a) + 13) % 26) + a);
cb.put(pos, c);
}
}
}
//------------------------------------------------ --------
/**
* Rot13 Chars et のエンコーダ実装、および
* 以下の一致するデコーダー クラスは、「impl」メソッドもオーバーライドする必要があります。
* implOnMalformedInput( ) など、
*baseEncoder オブジェクト。これはハッカーの演習として残されています。
*/
プライベート クラス Rot13Encoder は CharsetEncoder を拡張します {
プライベート CharsetEncoder BaseEncoder;
/**
* コンストラクター。Charset オブジェクトを使用してスーパークラス コンストラクターを呼び出します。
* およびデリゲート エンコーダーからのエンコーディング サイズ。
*/
Rot13Encoder(Charset cs, CharsetEncoderbaseEncoder) {
super(cs,baseEncoder.averageBytesPerChar(),baseEncoder
.maxBytesPerChar());
this.baseEncoder = BaseEncoder;
}
/**
* エンコードループの実装 まず、Rot13 を適用します。
* CharBuffer にアルゴリズムをスクランブルし、エンコーダーをリセットします。
* 基本文字セットを指定し、実際の処理を行うためにその encode() メソッドを呼び出します。
* エンコーディングは、ラテン語以外の文字セットでは正しく動作しない可能性があります。
* 渡された CharBuffer は読み取り専用であるか、呼び出し元によって再利用される場合があります。
* 他の目的があるため、これを複製し、Rot13 エンコーディングを適用します。
* 入力バッファの位置を次へ進めたいと考えています。
* 消費された文字数を反映します。
*/
protected CoderResult encodeLoop(CharBuffer cb, ByteBuffer bb) {
CharBuffer tmpcb = CharBuffer.allocate(cb.remaining());
while (cb.hasRemaining()) {
tmpcb.put(cb.get());
}
tmpcb.rewind();
rot13(tmpcb);
BaseEncoder.reset();
CoderResult cr = BaseEncoder.encode(tmpcb, bb, true);
// エラーまたは出力オーバーフローの場合は、調整する必要があります
// 一致する入力バッファの位置
// 実際に一時バッファから消費された場合。
// アンダーフロー (すべての入力が消費される)、これは何も行われません。
cb.position(cb.position() - tmpcb.remaining());
リターン(cr);
}
}
//------------------------------------------------ --------
/**
* Rot13 Charset のデコーダー実装。
*/
プライベート クラス Rot13Decoder は CharsetDecoder を拡張します {
プライベート CharsetDecoder ベースデコーダ;
/**
* コンストラクター。Charset オブジェクトを使用してスーパークラス コンストラクターを呼び出します。
* デリゲート デコーダーから文字/バイト値を渡します。
*/
Rot13Decoder(Charset cs, CharsetDecoderbaseDecoder) {
super(cs,baseDecoder.averageCharsPerByte(),baseDecoder
.maxCharsPerByte());
this.baseDecoder = BaseDecoder;
}
/**
* デコードループの実装 まず、デコーダをリセットします。
* 基本文字セット。それを呼び出してバイトを文字にデコードします。
* 結果コードを保存すると、CharBuffer がスクランブル解除されます。
* Rot13 アルゴリズムと結果コードが返される場合、これは機能しない可能性があります。
* 非ラテン語の文字セットに対して適切に。
*/
protected CoderResult decodeLoop(ByteBuffer bb, CharBuffer cb) {
BaseDecoder.reset();
coderresult result = badedecoder.decode(bb、cb、true);
ROT13(CB);
return(result);
}
}
// ----------------------------------------------------------- --------
/**
* rot13 charsetの単位テスト
*コマンドラインに名前が付けられている場合、またはargsが提供されていない場合はstdin、および
* X -ROT13 CHARSETエンコードを介して内容をSTDOUTに書き込みます
* ROT13アルゴリズムによって実装される「暗号化」は対称です
*たとえば、Javaソースコードなどのプレーンテキストファイルでは、
*スクランブルバージョンに戻ってきます
*オリジナルのプレーンテキストドキュメント。
*/
public static void main(string [] argv)スロー例外{
bufferedReader;
if(argv。length> 0){
//名前付きファイルを開きます
in = new BufferedReader(new fileReader(argv [0]));
} それ以外 {
// stdinの周りにバッファレッドリーダーをラップします
in = new BufferedReader(new inputStreamReader(System.in));
}
// rot13エンコーディングを使用するprintStreamを作成します
printStream out = new PrintStream(system.out、false、 "x -rot13");
文字列 s = null;
//すべての入力を読み取り、出力に書き込みます。
//データがprintStreamを通過すると、
// rot13エンコードされます。
while((s = in.readline())!= null){
out.println(s);
}
out.flush();
}
}
例6-4
パッケージcom.ronsoft.books.nio.charset;
java.nio.charset.charsetをインポートします。
java.nio.charset.spi.charsetproviderをインポートします。
java.util.HashSet をインポートします。
java.util.iteratorをインポートします。
/**
*提供された充電器を利用可能にするcharsetproviderクラス
* Ronsoft
*登録されたiana charsetではないので、名前は「x-」で始まり、名前を避けるために始まります
*オフカルの充電と衝突します。
*
*このcharsetproviderをアクティブにするには、ファイルをに追加する必要があります
*次の場所でのJVMランタイムのクラスパス:
* Meta-inf/services/java.nio.charsets.spi.charsetprovider
*
*そのファイルには、このクラスの完全な資格のある名前のラインが含まれている必要があります
*単独で行:com.ronsoft.books.nio.Charset.RonsoftCharsetProvider Java
* NIO 216
*
* java.nio.charsets.spi.charsetproviderのJavadocページを参照してください
* 詳細。
*
* @author ron hitchens([email protected])
*/
Public Class RonsoftCharsetProviderはCharSetProviderを拡張します{
//提供するcharsetの名前
プライベート静的最終文字列charset_name = "x-rot13";
// charsetオブジェクトのハンドル
プライベートチャーセットrot13 = null;
/**
*コンストラクター、チャーセットオブジェクトをインスタンス化し、参照を保存します。
*/
public ronsoftcharsetprovider(){
this.rot13 = new Rot13Charset(charset_name、new String [0]);
}
/**
* Charset staticメソッドによって呼び出され、特定の名前のcharset
*これはこのチャーセットの名前です(エイリアスはありません)。
* rot13 charset、それはnullを返します。
*/
パブリックチャーセットcharsetforname(string charsetname){
if(charsetname.equalsignorecase(charset_name)){
return(rot13);
}
return(null);
}
/**
*私たちが提供するチャーセットオブジェクトのセットに反復器を返します。
*
* @returnすべてのcharsetへの参照を含むイテレーターオブジェクト
*このクラスが提供するオブジェクト。
*/
public Iterator <Charset> charsets(){
Hashset <Charset> set = new Hashset <Charset>(1);
set.add(rot13);
return(set.iterator());
}
}
例6-1の文字セットリストにx -rot13を追加すると、この追加の出力が生成されます。
charset:x-rot13
入力:chmaana?
エンコード:
0:c2(o)
1:BF(Q)
2:5a(z)
3:6e(n)
4:C3(¡)
5:B1(±)
6:6e(n)
7:61(a)
8:6e(n)
9:3f(?)
Charset(文字セットクラス)
バイトのシーケンスとして文字セットとは異なる文字シーケンスを表すために使用されるエンコードをカプセル化する文字セットエンコードスキーム。
CharSeCencoder(キャラクターセットエンコーディングクラス)
エンコードエンジンは、文字シーケンスをバイトシーケンスに変換します。バイトシーケンスをデコードして、ソース文字シーケンスを再構築できます。
charsetdecoder(charset decoderクラス)
デコードエンジンは、エンコードされたバイトシーケンスを文字シーケンスに変換します。
charsetprovider spi(charsetプロバイダーSPI)
ランタイム環境で使用するサーバーベンダーメカニズムを介して、CharSetの実装を見つけて利用可能にします。