Dasar-dasar kumpulan karakter:
Kumpulan karakter
Kumpulan karakter, yaitu simbol dengan semantik khusus. Huruf "A" adalah karakter. "%" juga merupakan karakter. Ia tidak memiliki nilai numerik intrinsik dan tidak memiliki koneksi langsung ke ASC II, Unicode, atau bahkan komputer. Simbol sudah ada jauh sebelum komputer.
Kumpulan karakter berkode
Nilai numerik diberikan ke kumpulan karakter. Tetapkan kode ke karakter sehingga mereka dapat mengekspresikan hasil numerik menggunakan kumpulan pengkodean karakter tertentu. Kumpulan karakter berkode lainnya dapat memberikan nilai berbeda ke karakter yang sama. Pemetaan kumpulan karakter biasanya ditentukan oleh organisasi standar, seperti USASCII, ISO 8859-1, Unicode (ISO 10646-1), dan JIS X0201.
Skema pengkodean karakter
Pemetaan anggota kumpulan karakter yang dikodekan ke oktet (byte 8-bit). Skema pengkodean mendefinisikan bagaimana urutan pengkodean karakter dinyatakan sebagai urutan byte. Nilai pengkodean karakter tidak harus sama dengan byte pengkodean, juga tidak perlu hubungan satu-ke-satu atau satu-ke-banyak. Pada prinsipnya, pengkodean dan dekode kumpulan karakter dapat didekati sebagai serialisasi dan deserialisasi objek.
Biasanya pengkodean data karakter digunakan untuk transmisi jaringan atau penyimpanan file. Skema pengkodean bukanlah kumpulan karakter, melainkan pemetaan, tetapi karena hubungannya yang erat, sebagian besar pengkodean dikaitkan dengan kumpulan karakter terpisah. Misalnya, UTF-8,
Hanya digunakan untuk menyandikan kumpulan karakter Unicode. Meskipun demikian, dimungkinkan untuk menggunakan satu skema pengkodean untuk menangani beberapa rangkaian karakter. Misalnya, EUC dapat mengkodekan karakter untuk beberapa bahasa Asia.
Gambar 6-1 adalah ekspresi grafis yang menggunakan skema pengkodean UTF-8 untuk mengkodekan rangkaian karakter Unicode ke dalam rangkaian byte. UTF-8 mengkodekan nilai kode karakter kurang dari 0x80 menjadi nilai byte tunggal (standar ASC II). Semua karakter Unicode lainnya dikodekan sebagai urutan multibyte 2 hingga 6 byte (http://www.ietf.org/rfc/rfc2279.txt).
rangkaian karakter
Istilah rangkaian karakter didefinisikan dalam RFC2278 (http://ietf.org/rfc/rfc2278.txt). Ini adalah kumpulan kumpulan karakter yang dikodekan dan skema pengkodean karakter. Kelas paket java.nio.charset adalah Charset, yang merangkum ekstraksi kumpulan karakter.
1111111111111111
Unicode adalah pengkodean karakter 16-bit. Ia berupaya menyatukan rangkaian karakter semua bahasa di dunia ke dalam satu pemetaan yang komprehensif. Ini telah mendapatkan tempatnya, tetapi ada banyak pengkodean karakter lain yang digunakan secara luas saat ini.
Sebagian besar sistem operasi masih berorientasi byte dalam hal I/O dan penyimpanan file, jadi tidak peduli pengkodean apa yang digunakan, Unicode atau pengkodean lainnya, masih ada kebutuhan untuk mengkonversi antara urutan byte dan pengkodean kumpulan karakter.
Kelas-kelas yang terdiri dari paket java.nio.charset memenuhi kebutuhan ini. Ini bukan pertama kalinya platform Java menangani pengkodean kumpulan karakter, tetapi ini adalah solusi yang paling sistematis, komprehensif, dan fleksibel. Paket java.nio.charset.spi menyediakan Server Provisioning Interface (SPI) sehingga encoder dan decoder dapat dipasang sesuai kebutuhan.
Kumpulan karakter: Nilai default ditentukan saat startup JVM dan bergantung pada lingkungan sistem operasi yang mendasarinya, lokal, dan/atau konfigurasi JVM. Jika Anda memerlukan kumpulan karakter tertentu, cara paling aman adalah memberi nama secara eksplisit. Jangan berasumsi bahwa penerapan default sama dengan lingkungan pengembangan Anda. Nama kumpulan karakter tidak peka huruf besar-kecil, artinya huruf besar dan huruf kecil dianggap sama saat membandingkan nama kumpulan karakter. Internet Assigned Names Authority (IANA) menyimpan semua nama kumpulan karakter yang terdaftar secara resmi.
Contoh 6-1 mendemonstrasikan cara menerjemahkan karakter ke dalam urutan byte menggunakan implementasi Charset yang berbeda.
Contoh 6-1. Menggunakan pengkodean kumpulan karakter standar
paket com.ronsoft.books.nio.charset;
impor java.nio.charset.Charset;
impor java.nio.ByteBuffer;
/**
* Tes pengkodean Charset. Jalankan string input yang sama, yang berisi beberapa
* karakter non-ascii, melalui beberapa encoder Charset dan membuang hex
* nilai urutan byte yang dihasilkan.
*
* @penulis Ron Hitchens ([email protected])
*/
Tes Encode kelas publik {
public static void main(String[] argv) memunculkan Pengecualian {
// Ini adalah urutan karakter yang akan dikodekan
Masukan string = "/u00bfMa/u00f1ana?";
// daftar rangkaian karakter yang akan dikodekan
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]), masukan);
}
}
/**
* Untuk Charset dan string input tertentu, encode karakternya dan cetak
* menghasilkan pengkodean byte dalam bentuk yang dapat dibaca.
*/
private static void doEncode(Charset cs, masukan string) {
ByteBuffer bb = cs.encode(masukan);
System.out.println("Charset: " + cs.nama());
System.out.println("Masukan: "+masukan);
System.out.println("Dikodekan: ");
for (int i = 0; bb.hasRemaining(); i++) {
int b = bb.get();
int ival = ((int) b) & 0xff;
karakter c = (karakter) ival;
// Jaga agar perataan tabel tetap cantik
jika (saya <10)
Sistem.keluar.cetak(" ");
//Cetak nomor indeks
Sistem.keluar.cetak(" " + i + ": ");
// Output dengan format lebih baik akan hadir suatu hari nanti...
jika (ival <16)
Sistem.keluar.cetak("0");
// Cetak nilai hex dari byte
Sistem.keluar.cetak(Integer.toHexString(ival));
// Jika byte tampaknya merupakan nilai a
// karakter yang dapat dicetak, tidak ada jaminan
// itu akan terjadi.
if (Karakter.isWhitespace(c) || Karakter.isISOControl(c)) {
Sistem.keluar.println("");
} kalau tidak {
Sistem.keluar.println(" (" + c + ")");
}
}
Sistem.keluar.println("");
}
}
Rangkaian Karakter: ISO-8859-1
Masukan: ?Ma?ana?
Dikodekan:
0:20
1: bf (?)
2: 4d (L)
3:61(a)
4: f1 (?)
5:61(a)
6: 6e(n)
7:61(a)
8: 3f (?)
Kumpulan karakter: UTF-8
Masukan: ?Ma?ana?
Dikodekan:
0:20
1: c2 (?)
2: bf (?)
3: 4d (L)
4:61(a)
5: c3 (?)
6: b1 (±)
7:61(a)
8: 6e(n)
9:61(a)
10: 3f (?)
Rangkaian Karakter: UTF-16BE
Masukan: ?Ma?ana?
Dikodekan:
0:00
1:20
02:00
3: bf (?)
04:00
5: 4d (L)
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 (?)
Rangkaian Karakter: UTF-16LE
Masukan: ?Ma?ana?
Dikodekan:
0:20
1:00
2: bf (?)
3:00
4: 4d (L)
5:00
6:61(a)
07:00
8: f1 (?)
9:00
10:61(a)
11:00
12: 6e(n)
13:00
14: 61 (a)
15:00
16: 3f (?)
17:00
Rangkaian Karakter: UTF-16
Masukan: ?Ma?ana?
Dikodekan:
0: fe (?)
1: ff (?)
02:00
3:20
04:00
5: bf (?)
6:00
7: 4d (L)
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 (?)
paket java.nio.charset;
kelas abstrak publik Charset mengimplementasikan Comparable
{
boolean statis publik isSupported (String charsetName)
Charset statis publik untukNama (String charsetName)
SortedMap statis publik tersediaCharsets()
nama String akhir publik()
alias Set akhir publik()
String publik nama tampilan()
public String displayName (Lokal lokal)
boolean akhir publik isRegistered()
canEncode boolean publik()
abstrak publik CharsetEncoder newEncoder();
penyandian ByteBuffer akhir publik (CharBuffer cb)
penyandian ByteBuffer akhir publik (String str)
abstrak publik CharsetDecoder newDecoder();
dekode CharBuffer akhir publik (ByteBuffer bb)
boolean abstrak publik berisi (Charset cs);
boolean akhir publik sama dengan (Objek ob)
perbandingan int akhir publikTo (Objek ob)
Kode hash int akhir publik()
String akhir publik toString()
}
Seringkali, hanya penjual JVM yang memperhatikan aturan ini. Namun, jika Anda berencana menggunakan rangkaian karakter Anda sendiri sebagai bagian dari aplikasi Anda, akan sangat membantu jika Anda mengetahui apa yang tidak boleh dilakukan. Anda harus mengembalikan false untuk isRegistered() dan memberi nama rangkaian karakter Anda dimulai dengan "X -".
Perbandingan kumpulan karakter:
kelas abstrak publik Charset mengimplementasikan Comparable
{
// Ini adalah sebagian daftar API
boolean abstrak publik berisi (Charset cs);
boolean akhir publik sama dengan (Objek ob)
perbandingan int akhir publikTo (Objek ob)
Kode hash int akhir publik()
String akhir publik toString()
}
Encoder kumpulan karakter: Kumpulan karakter terdiri dari kumpulan karakter yang dikodekan dan skema pengkodean terkait. Kelas CharsetEncoder dan CharsetDecoder mengimplementasikan skema konversi.
Satu catatan tentang CharsetEncoder API: Pertama, semakin sederhana bentuk encode(), semakin nyaman pengkodean CharBuffer yang Anda berikan di ByteBuffer yang dialokasikan ulang menggabungkan semua pengkodean. Ini adalah metode terakhir yang dipanggil ketika Anda memanggil encode() secara langsung pada kelas Charset.
Aliran bawah
Meluap
Masukan salah
Karakter yang tidak dapat dipetakan
Saat melakukan pengkodean, jika pembuat enkode menemukan masukan yang rusak atau tidak dapat dipetakan, objek hasil akan dikembalikan. Anda juga dapat menguji karakter individual, atau rangkaian karakter, untuk menentukan apakah karakter tersebut dapat dikodekan. Berikut cara memeriksa apakah pengkodean dapat dilakukan:
paket java.nio.charset;
kelas abstrak publik CharsetEncoder
{
// Ini adalah sebagian daftar API
canEncode boolean publik (char c)
canEncode boolean publik (CharSequence cs)
}
LAPORAN
Perilaku default saat membuat CharsetEncoder. Perilaku ini menunjukkan bahwa kesalahan pengkodean harus dilaporkan dengan mengembalikan objek CoderResult yang disebutkan sebelumnya.
Abaikan (abaikan)
Menunjukkan bahwa kesalahan pengkodean harus diabaikan dan masukan yang salah harus dibatalkan jika keluar dari posisinya.
MENGGANTI
Kesalahan pengkodean ditangani dengan membatalkan masukan kesalahan dan mengeluarkan urutan byte pengganti saat ini yang ditentukan untuk CharsetEncoder ini.
Ingat, pengkodean kumpulan karakter mengubah karakter menjadi urutan byte sebagai persiapan untuk decoding nanti. Jika urutan pengganti tidak dapat didekodekan menjadi urutan karakter yang valid, urutan byte yang dikodekan menjadi tidak valid.
Kelas CoderResult: Objek CoderResult dikembalikan oleh objek CharsetEncoder dan CharsetDecoder:
paket java.nio.charset;
kelas publik CoderResult {
CoderResult OVERFLOW akhir statis publik
CoderResult UNDERFLOW akhir statis publik
boolean publik isUnderflow()
boolean publik isOverflow()
<span style="white-space:pre"> </span>isError boolean publik()
boolean publik isMalformed()
boolean publik isUnmappable()
panjang int publik()
CoderResult statis publik malformedForLength (panjang int)
CoderResult statis publik unmappableForLength (panjang int)
<span style="white-space:pre"> </span>public void throwException() menampilkan CharacterCodingException
}
paket java.nio.charset;
kelas abstrak publik CharsetDecoder
{
// Ini adalah sebagian daftar API
reset CharsetDecoder akhir publik()
dekode CharBuffer akhir publik (ByteBuffer masuk)
melempar CharacterCodingException
dekode CoderResult akhir publik (ByteBuffer masuk, CharBuffer keluar,
boolean endOfInput)
flush CoderResult akhir publik (CharBuffer keluar)
}
1. Reset decoder dengan memanggil reset() untuk menempatkan decoder dalam keadaan siap menerima input.
2. Setel endOfInput ke false dan jangan panggil atau panggil decode() beberapa kali untuk memasok byte ke mesin decoding. Saat decoding berlangsung, karakter akan ditambahkan ke CharBuffer yang diberikan.
3. Setel endOfInput ke true dan panggil decode() satu kali untuk memberi tahu decoder bahwa semua input telah diberikan.
4. Panggil flush() untuk memastikan bahwa semua karakter yang didekode telah dikirim ke output.
Contoh 6-2 mengilustrasikan cara mengkodekan aliran byte yang mewakili pengkodean kumpulan karakter.
Contoh 6-2. Penguraian kode kumpulan karakter
paket com.ronsoft.books.nio.charset;
import java.nio.*;
import java.nio.charset.*;
import java.nio.channels.*;
import java.io.*;
/**
* Uji decoding rangkaian karakter.
*
* @penulis Ron Hitchens ([email protected])
*/
kelas publik CharsetDecode {
/**
* Uji decoding charset dalam kasus umum, mendeteksi dan menangani buffer
* under/overflow dan menghapus status decoder di akhir input kode ini
* membaca dari stdin dan menerjemahkan aliran byte yang dikodekan ASCII ke karakter
* Karakter yang didekodekan ditulis ke stdout. Ini sebenarnya adalah 'kucing'
* masukkan file ascii, tetapi pengkodean charset lain dapat digunakan dengan mudah
* menentukannya pada baris perintah.
*/
public static void main(String[] argv) melempar IOException {
// Rangkaian karakter default adalah ASCII standar
String charsetName = "ISO-8859-1";
// Nama rangkaian karakter dapat ditentukan pada baris perintah
if (argv.length > 0) {
charsetName = argv[0];
}
// Bungkus Saluran di sekitar stdin, bungkus saluran di sekitar stdout,
// temukan nama Charset dan teruskan ke metode deco de.
// Jika rangkaian karakter bernama tidak valid, maka akan terjadi pengecualian tipe
// UnsupportedCharsetException akan dilempar.
decodeChannel(Channels.newChannel(System.in), OutputStreamWriter baru(
Sistem.keluar), Charset.forName(charsetName));
}
/**
* Metode statis tujuan umum yang membaca byte dari Saluran, menerjemahkan kode
* mereka menurut
*
* @param sumber
* Objek ReadableByteChannel yang akan dibaca ke EOF sebagai a
* sumber byte yang disandikan.
* @param penulis
* Objek Writer tempat karakter yang didekodekan akan ditulis.
* @param rangkaian karakter
* Objek Charset, yang CharsetDecodernya akan digunakan untuk melakukan
* penguraian kumpulan karakter
*/
public static void decodeChannel (sumber ReadableByteChannel, Penulis penulis,
Charset charset) menampilkan UnsupportedCharsetException, IOException {
// Dapatkan instance decoder dari Charset
Dekoder CharsetDecoder = charset.newDecoder();
// Perintahkan decoder untuk mengganti karakter buruk dengan tanda default
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
// Alokasikan ukuran buffer masukan dan keluaran yang sangat berbeda
// untuk tujuan pengujian
ByteBuffer bb = ByteBuffer.allocationDirect(16 * 1024);
CharBuffer cb = CharBuffer.alokasikan(57);
// Buffer mulai kosong; menunjukkan input diperlukan
Hasil CoderResult = CoderResult.UNDERFLOW;
boolean eof = salah;
sementara (!eof) {
// Dekoder buffer masukan menginginkan lebih banyak masukan
if (hasil == CoderResult.UNDERFLOW) {
// decoder menggunakan semua input, bersiap untuk mengisi ulang
bb.hapus();
// Isi buffer input, perhatikan EOF
eof = (sumber.baca(bb) == -1);
// Siapkan buffer untuk membaca dengan decoder
bb.flip();
}
// Dekode byte masukan ke karakter keluaran;
hasil = decoder.decode(bb, cb, eof);
// Jika buffer keluaran penuh, tiriskan keluaran
if (hasil == CoderResult.OVERFLOW) {
drainCharBuf(cb, penulis);
}
}
// Hapus semua status yang tersisa dari decoder, hati-hati
// untuk mendeteksi luapan buffer keluaran
while (decoder.flush(cb) == CoderResult.OVERFLOW) {
drainCharBuf(cb, penulis);
}
// Tiriskan semua karakter yang tersisa di buffer keluaran
drainCharBuf(cb, penulis);
// Tutup saluran; dorong semua data yang di-buffer ke stdout
sumber.close();
penulis.flush();
}
/**
* Metode pembantu untuk menguras buffer char dan menulis kontennya ke yang diberikan
* Objek penulis. Setelah kembali, buffer kosong dan siap diisi ulang.
*
* @param cb
* CharBuffer berisi karakter yang akan ditulis.
* @param penulis
* Objek Penulis untuk menggunakan karakter di cb.
*/
static void drainCharBuf(CharBuffer cb, Penulis penulis) melempar IOException {
cb.flip(); // Siapkan buffer untuk pengurasan
// Ini menulis karakter yang terdapat dalam CharBuffer tapi
// sebenarnya tidak mengubah status buffer.
// Jika buffer char sedang dikosongkan oleh panggilan ke get(),
// satu loop mungkin diperlukan di sini.
if (cb.hasRemaining()) {
penulis.write(cb.toString());
}
cb.clear(); // Siapkan buffer untuk diisi kembali
}
}
Sebelum menelusuri API, penting untuk menjelaskan cara kerja Charset SPI. Paket java.nio.charset.spi hanya berisi satu kelas ekstraksi, CharsetProvider. Implementasi konkrit kelas ini memberikan informasi terkait objek Charset yang disediakannya. Untuk menentukan kumpulan karakter khusus, Anda harus terlebih dahulu membuat implementasi spesifik Charset, CharsetEncoder, dan CharsetDecoder dari paket java.nio.charset. Anda kemudian membuat subkelas khusus CharsetProvider yang akan menyediakan kelas tersebut ke JVM.
Buat kumpulan karakter khusus:
Paling tidak yang harus Anda lakukan adalah membuat subkelas java.nio.charset.Charset, menyediakan implementasi konkret dari tiga metode ekstraksi, dan konstruktor. Kelas Charset tidak memiliki konstruktor default dan tanpa parameter. Ini berarti kelas kumpulan karakter khusus Anda harus memiliki konstruktor, meskipun kelas tersebut tidak menerima parameter. Ini karena Anda harus memanggil konstruktor Charset pada waktu pembuatan instance (dengan memanggil super() di awal konstruktor Anda), sehingga memberikan nama dan alias spesifikasi charset Anda. Melakukan hal ini memungkinkan metode di kelas Charset menangani hal-hal yang berhubungan dengan nama untuk Anda, jadi itu adalah hal yang baik.
Demikian pula, Anda perlu menyediakan implementasi konkret dari CharsetEncoder dan CharsetDecoder. Ingatlah bahwa kumpulan karakter adalah kumpulan karakter yang dikodekan dan skema pengkodean/penguraian kode. Seperti yang kita lihat sebelumnya, pengkodean dan decoding hampir simetris di tingkat API. Diskusi singkat tentang apa yang diperlukan untuk mengimplementasikan encoder diberikan di sini: hal yang sama berlaku untuk membuat decoder.
Mirip dengan Charset, CharsetEncoder tidak memiliki konstruktor default, jadi Anda perlu memanggil super() di konstruktor kelas konkret, dengan menyediakan parameter yang diperlukan.
Untuk menyediakan implementasi CharsetEncoder Anda sendiri, Anda setidaknya harus menyediakan metode encodeLoop () yang konkret. Untuk algoritma pengkodean sederhana, implementasi default dari metode lain akan berfungsi dengan baik. Perhatikan bahwa encodeLoop() mengambil parameter yang mirip dengan encode(), tidak termasuk flag Boolean. Metode encode () mewakili pengkodean sebenarnya ke encodeLoop(), yang hanya perlu memperhatikan karakter yang dikonsumsi dari parameter CharBuffer, dan menampilkan byte yang dikodekan ke ByteBuffer yang disediakan.
Sekarang kita telah melihat cara mengimplementasikan kumpulan karakter khusus, termasuk encoder dan decoder terkait, mari kita lihat cara menghubungkannya ke JVM sehingga kita dapat menjalankan kode menggunakan mereka.
Berikan kumpulan karakter khusus Anda:
Untuk menyediakan implementasi Charset Anda sendiri ke lingkungan runtime JVM, Anda harus membuat subkelas konkret dari kelas CharsetProvider di java.nio.charsets.-spi, masing-masing dengan konstruktor tanpa parameter. Konstruktor tanpa parameter penting karena kelas CharsetProvider Anda akan ditempatkan dengan membaca nama file konfigurasi yang sepenuhnya memenuhi syarat. String nama kelas ini kemudian akan diimpor ke Class.newInstance() untuk memberi contoh penyedia Anda, yang hanya bekerja melalui konstruktor tanpa parameter.
File konfigurasi yang dibaca oleh JVM menemukan penyedia kumpulan karakter, yang diberi nama java.nio.charset.spi.CharsetProvider. Itu terletak di direktori sumber (META-INF/services) di classpath JVM. Setiap JavaArchive (JAR) memiliki direktori META-INF yang berisi informasi tentang kelas dan sumber daya di JAR tersebut. Direktori bernama META-INF juga dapat ditempatkan di bagian atas direktori reguler di classpath JVM.
CharsetProvider API hampir tidak berguna. Pekerjaan sebenarnya dalam menyediakan kumpulan karakter khusus terjadi dalam pembuatan kelas Charset, CharsetEncoder, dan CharsetDecoder khusus. CharsetProvider hanyalah fasilitator antara rangkaian karakter Anda dan lingkungan runtime.
Contoh 6-3 mendemonstrasikan penerapan Charset dan CharsetProvider kustom, termasuk kode pengambilan sampel yang mengilustrasikan penggunaan rangkaian karakter, pengkodean dan penguraian kode, serta Charset SPI. Contoh 6-3 mengimplementasikan Charset khusus.
Contoh 6-3. Kumpulan karakter Rot13 yang disesuaikan
paket com.ronsoft.books.nio.charset;
impor java.nio.CharBuffer;
impor java.nio.ByteBuffer;
impor java.nio.charset.Charset;
impor java.nio.charset.CharsetEncoder;
impor java.nio.charset.CharsetDecoder;
impor java.nio.charset.CoderResult;
import java.util.Map;
impor java.util.Iterator;
impor java.io.Writer;
impor java.io.PrintStream;
impor java.io.PrintWriter;
impor java.io.OutputStreamWriter;
impor java.io.BufferedReader;
impor java.io.InputStreamReader;
impor java.io.FileReader;
/**
* Implementasi Charset yang melakukan pengkodean Rot13
* Algoritma kebingungan teks sederhana yang menggeser karakter alfabet sebanyak 13
* sehingga 'a' menjadi 'n', 'o' menjadi 'b', dan seterusnya. Algoritma ini dipopulerkan
* Oleh forum diskusi Usenet bertahun-tahun yang lalu untuk menutupi kata-kata nakal, sembunyikan
* Jawaban pertanyaan, dan sebagainya. Algoritma Rot13 simetris, diterapkan
* ke teks yang telah diacak oleh Rot13 akan memberikan Anda yang asli
* teks yang tidak diacak.
*
* Menerapkan pengkodean Charset ini ke aliran keluaran akan menyebabkan semua yang Anda lakukan
* tulis ke aliran itu untuk diacak Rot13 seperti yang tertulis
* ke aliran input menyebabkan data yang dibaca menjadi Rot13 diurai saat dibaca.
*
* @penulis Ron Hitchens ([email protected])
*/
kelas publik Rot13Charset memperluas Charset {
// nama pengkodean rangkaian karakter dasar yang kita delegasikan
String akhir statis pribadi BASE_CHARSET_NAME = "UTF-8";
// Tangani rangkaian karakter sebenarnya yang akan kita gunakan untuk transcoding di antaranya
// karakter dan byte. Melakukan hal ini memungkinkan kita untuk menerapkan Rot13
// algoritma untuk pengkodean charset multibyte
// Karakter alfa ASCII akan diputar, apa pun pengkodean dasarnya.
Basis CharsetCharset;
/**
* Konstruktor untuk rangkaian karakter Rot13. Panggil konstruktor superkelas untuk
* sampaikan nama yang akan kita kenal. Lalu simpan referensi ke
* delegasikan Charset.
*/
dilindungi Rot13Charset(String kanonik, String[] alias) {
super(kanonik, alias);
// Simpan rangkaian karakter dasar yang akan kita delegasikan
baseCharset = Charset.forName(BASE_CHARSET_NAME);
}
//------------------------------------------------ ----------
/**
* Dipanggil oleh pengguna Charset ini untuk mendapatkan implementasi ini
* membuat instance kelas privat (didefinisikan di bawah) dan meneruskannya
* encoder dari basis Charset.
*/
CharsetEncoder publik newEncoder() {
kembalikan Rot13Encoder baru (ini, baseCharset.newEncoder());
}
/**
* Dipanggil oleh pengguna Charset ini untuk mendapatkan decoder implementasi ini
* membuat instance kelas privat (didefinisikan di bawah) dan meneruskannya
* decoder dari basis Charset.
*/
CharsetDecoder publik Decoder baru() {
kembalikan Rot13Decoder baru (ini, baseCharset.newDecoder());
}
/**
* Metode ini harus diterapkan dengan Charsets yang konkrit.
* yang aman.
*/
boolean publik berisi(Charset cs) {
kembali (salah);
}
/**
* Rutin umum untuk memutar semua karakter alfa ASCII yang diberikan
* CharBuffer sebesar 13. Perhatikan bahwa kode ini secara eksplisit membandingkan bagian atas dan
* karakter ASCII huruf kecil daripada menggunakan metode
* Character.isLowerCase dan Character.isUpperCase
* Skema putar-demi-13 hanya berfungsi dengan baik untuk karakter alfabet
* rangkaian karakter ASCII dan metode tersebut dapat mengembalikan nilai true untuk Unicode non-ASCII
* karakter.
*/
kekosongan pribadi rot13(CharBuffer cb) {
for (int pos = cb.posisi(); pos < cb.batas(); pos++) {
char c = cb.get(pos);
karakter a = '/u0000';
// Apakah itu huruf alfa kecil?
jika ((c >= 'a') && (c <= 'z')) {
a = 'sebuah';
}
// Apakah itu huruf alfa besar?
jika ((c >= 'A') && (c <= 'Z')) {
a = 'A';
}
// Jika salah satunya, naikkan menjadi 13
jika (a != '/u0000') {
c = (karakter) ((((c - a) + 13) % 26) + a);
cb.put(pos, c);
}
}
}
//------------------------------------------------ --------
/**
* Implementasi encoder untuk Rot13 Chars et
* kelas dekoder yang cocok di bawah, juga harus mengganti metode "impl",
* seperti implOnMalformedInput( ) dan melakukan panggilan passthrough ke
* objek baseEncoder. Itu dibiarkan sebagai latihan untuk hacker.
*/
kelas pribadi Rot13Encoder memperluas CharsetEncoder {
baseEncoder CharsetEncoder pribadi;
/**
* Konstruktor, memanggil konstruktor superclass dengan objek Charset
* dan ukuran pengkodean dari encoder delegasi.
*/
Rot13Encoder(Charset cs, CharsetEncoder baseEncoder) {
super(cs, baseEncoder.averageBytesPerChar(), baseEncoder
.maxBytesPerChar());
ini.baseEncoder = baseEncoder;
}
/**
* Implementasi loop pengkodean. Pertama, kita menerapkan Rot13
* mengacak algoritma ke CharBuffer, lalu mereset encoder untuk
* Charset dasar dan panggil metode encode() untuk melakukan yang sebenarnya
* pengkodean. Ini mungkin tidak berfungsi dengan baik untuk rangkaian karakter non-Latin
* CharBuffer yang diteruskan dapat bersifat read-only atau digunakan kembali oleh pemanggil
* tujuan lain jadi kami menduplikasinya dan menerapkan pengkodean Rot13 ke
* copy. Kami ingin memajukan posisi buffer input ke
* mencerminkan karakter yang dikonsumsi.
*/
dilindungi CoderResult encodeLoop(CharBuffer cb, ByteBuffer bb) {
CharBuffer tmpcb = CharBuffer.alokasikan(cb.sisa());
while (cb.hasRemaining()) {
tmpcb.put(cb.get());
}
tmpcb.rewind();
busuk13(tmpcb);
baseEncoder.reset();
CoderResult cr = baseEncoder.encode(tmpcb, bb, benar);
// Jika error atau output meluap, kita perlu melakukan penyesuaian
// posisi buffer input cocok dengan apa
// benar-benar dikonsumsi dari buffer sementara If
// underflow (semua input terpakai), ini dilarang.
cb.posisi(cb.posisi() - tmpcb.sisa());
kembali(kr);
}
}
//------------------------------------------------ --------
/**
* Implementasi dekoder untuk Rot13 Charset.
*/
kelas pribadi Rot13Decoder memperluas CharsetDecoder {
baseDecoder CharsetDecoder pribadi;
/**
* Konstruktor, memanggil konstruktor superclass dengan objek Charset
* dan meneruskan nilai karakter/byte dari dekoder delegasi.
*/
Rot13Decoder(Charset cs, CharsetDecoder baseDecoder) {
super(cs, baseDecoder.averageCharsPerByte(), baseDecoder
.maxCharsPerByte());
ini.baseDecoder = baseDecoder;
}
/**
* Implementasi loop decoding. Pertama, kita mereset decoder untuk
* rangkaian karakter dasar, lalu panggil untuk memecahkan kode byte menjadi karakter,
* menyimpan kode hasil. CharBuffer kemudian diacak dengan
* Algoritma Rot13 dan kode hasil dikembalikan
* benar untuk rangkaian karakter non-Latin.
*/
decodeLoop CoderResult yang dilindungi(ByteBuffer bb, CharBuffer cb) {
baseDecoder.reset();
CoderRresult Hasil = bedandedEcoder.decode (BB, CB, true);
ROT13 (CB);
pengembalian (hasil);
}
}
// ------------------------------------------------- --------
/**
* Uji unit untuk charset ROT13.
* file jika dinamai pada baris perintah, atau stdin jika tidak ada arg disediakan, dan
* Tulis konten ke stdout melalui encoding charset x -rot13
* "Enkripsi" yang diimplementasikan oleh algoritma ROT13 bersifat simetris
* Dalam file teks biasa, seperti kode sumber java misalnya, akan menghasilkan a
* Versi orak -arik.
* Dokumen teks polos asli.
*/
public static void main (string [] argv) melempar pengecualian {
BufferedReader di;
if (argv. length> 0) {
// buka file yang disebutkan
di = BufferedReader baru (filereader baru (argv [0]));
} kalau tidak {
// Bungkus pembiakan di sekitar stdin
di = BufferedReader baru (inputStreamReader baru (System.in));
}
// Buat printstream yang menggunakan pengkodean ROT13
PrintStream out = printStream baru (System.out, false, "x -rot13");
String s = nol;
// Baca semua input dan tuliskan ke output.
// Saat data melewati printstream,
// Ini akan menjadi ROT13-encoded.
while ((s = in.readline ())! = null) {
out.println (s);
}
keluar.flush();
}
}
Contoh 6-4.
paket com.ronsoft.books.nio.charset;
impor java.nio.charset.charset;
impor java.nio.charset.spi.charsetProvider;
impor java.util.HashSet;
impor java.util.iterator;
/**
* Kelas CharsetProvider yang menyediakan charset yang disediakan oleh
* Ronsoft
* Bukan charset IANA terdaftar, jadi namanya dimulai dengan "X-" untuk menghindari nama
* Bentrokan dengan charset resmi.
*
* Untuk mengaktifkan CharsetProvider ini, perlu menambahkan file ke
* Classpath dari JVM Runtime di lokasi berikut:
* Meta-Inf/Services/java.nio.charsets.spi.charsetProvider
*
* File itu harus berisi baris dengan nama kelas ini yang memenuhi syarat
* Baris dengan sendirinya: com.ronsoft.books.nio.charset.ronsoftcharsetProvider java
* Nio 216
*
* Lihat halaman Javadoc untuk java.nio.charsets.spi.charsetProvider untuk penuh
* Detail.
*
* @Author Ron Hitchens ([email protected])
*/
kelas publik ronsoftcharsetProvider memperluas charsetprovider {
// Nama charset yang kami berikan
Private Static Final String charset_name = "X-rot13";
// pegangan ke objek charset
Private Charset ROT13 = NULL;
/**
* Konstruktor, instantiate objek charset dan simpan referensi.
*/
public ronsoftcharsetProvider () {
this.rot13 = rot13charset baru (charset_name, string baru [0]);
}
/**
* Dipanggil dengan metode statis charset untuk menemukan charset bernama tertentu
* Ini nama charset ini (kami tidak memiliki alias) lalu mengembalikan
* ROT13 Charset, Lain return null.
*/
Charset CharsetForname (String CharsetName) {
if (charsetname.equalsignorecase (charset_name)) {
return (ROT13);
}
return (null);
}
/**
* Mengembalikan iterator di atas set objek charset yang kami sediakan.
*
* @return objek iterator yang berisi referensi untuk semua charset
* Objek yang disediakan oleh kelas ini.
*/
Iterator publik <Charset> charsets () {
HashSet <Charset> set = hashset baru <Charset> (1);
set.add (rot13);
return (set.iterator ());
}
}
Menambahkan x -rot13 ke daftar set karakter dalam Contoh 6-1 menghasilkan output tambahan ini:
Charset: X-ROT13
Input: żmaana?
Dikodekan:
0: C2 (ż)
1: BF (ż)
2: 5a (z)
3: 6e (n)
4: C3 (Ă)
5: B1 (±)
6: 6e (n)
7:61 (a)
8: 6e (n)
9: 3f (?)
Charset (Kelas Set Karakter)
Skema penyandian set karakter yang merangkum pengkodean yang digunakan untuk mewakili urutan karakter yang berbeda dari karakter yang ditetapkan sebagai urutan byte.
Charsetencoder (Kelas Pengkodean Set Karakter)
Encoding Engine mengubah urutan karakter menjadi urutan byte. Urutan byte kemudian dapat diterjemahkan untuk merekonstruksi urutan karakter sumber.
CharsetDecoder (Kelas Decoder Charset)
Mesin decoding mengubah urutan byte yang dikodekan menjadi urutan karakter.
CharsetProvider SPI (penyedia charset SPI)
Temukan dan buat implementasi charset tersedia melalui mekanisme vendor server untuk digunakan di lingkungan runtime.