Основы набора символов:
Набор символов
Коллекция символов, то есть символов с особой семантикой. Буква «А» — это символ. «%» также является символом. Он не имеет внутреннего числового значения и не имеет прямой связи с ASC II, Unicode или даже с компьютерами. Символы существовали задолго до компьютеров.
Кодированный набор символов
Числовое значение присваивается набору символов. Назначайте коды символам, чтобы они могли выражать числовые результаты, используя определенный набор кодировок символов. Другие кодированные наборы символов могут присваивать одному и тому же символу разные значения. Сопоставления наборов символов обычно определяются организациями по стандартизации, такими как USASCII, ISO 8859-1, Unicode (ISO 10646-1) и JIS X0201.
Схема кодирования символов
Преобразование членов закодированного набора символов в октеты (8-битные байты). Схема кодирования определяет, как последовательность кодировок символов выражается как последовательность байтов. Значение кодировки символа не обязательно должно совпадать со значением кодирующего байта, а также не должно быть отношением один-к-одному или один-ко-многим. В принципе, кодирование и декодирование набора символов можно аппроксимировать как сериализацию и десериализацию объектов.
Обычно кодирование символьных данных используется для передачи по сети или хранения файлов. Схема кодирования — это не набор символов, а отображение, но из-за их тесной связи большинство кодировок связаны с отдельным набором символов. Например, UTF-8,
Используется только для кодирования наборов символов Юникода. Тем не менее, можно использовать одну схему кодирования для обработки нескольких наборов символов. Например, EUC может кодировать символы нескольких азиатских языков.
На рис. 6-1 показано графическое выражение, использующее схему кодировки UTF-8 для кодирования последовательности символов Юникода в последовательность байтов. UTF-8 кодирует значения кодов символов меньше 0x80 в однобайтовое значение (стандарт ASC II). Все остальные символы Юникода кодируются как многобайтовые последовательности длиной от 2 до 6 байтов (http://www.ietf.org/rfc/rfc2279.txt).
Кодировка
Термин «кодировка» определен в RFC2278 (http://ietf.org/rfc/rfc2278.txt). Это коллекция кодированных наборов символов и схем кодирования символов. Класс пакета java.nio.charset — Charset, который инкапсулирует извлечение набора символов.
1111111111111111
Юникод — это 16-битная кодировка символов. Он пытается объединить наборы символов всех языков мира в единое комплексное отображение. Она заслужила свое место, но сегодня широко используется множество других кодировок символов.
Большинство операционных систем по-прежнему ориентированы на байты с точки зрения ввода-вывода и хранения файлов, поэтому независимо от того, какая кодировка используется, Unicode или другие кодировки, все равно существует необходимость преобразования между последовательностями байтов и кодировками набора символов.
Классы, состоящие из пакета java.nio.charset, удовлетворяют эту потребность. Это не первый раз, когда платформа Java имеет дело с кодировкой набора символов, но это наиболее систематическое, комплексное и гибкое решение. Пакет java.nio.charset.spi предоставляет интерфейс обеспечения сервера (SPI), позволяющий подключать кодеры и декодеры по мере необходимости.
Набор символов: значение по умолчанию определяется при запуске JVM и зависит от базовой среды операционной системы, языкового стандарта и/или конфигурации JVM. Если вам нужен определенный набор символов, безопаснее всего указать его явно. Не думайте, что развертывание по умолчанию совпадает с вашей средой разработки. Имена наборов символов не чувствительны к регистру, то есть прописные и строчные буквы считаются одинаковыми при сравнении имен наборов символов. Управление по присвоению имен в Интернете (IANA) поддерживает все официально зарегистрированные имена наборов символов.
Пример 6-1 демонстрирует, как преобразовать символы в последовательности байтов, используя различные реализации Charset.
Пример 6-1. Использование стандартной кодировки набора символов.
пакет com.ronsoft.books.nio.charset;
импортировать java.nio.charset.Charset;
импортировать java.nio.ByteBuffer;
/**
* Тест кодировки кодировки. Запустите ту же входную строку, которая содержит некоторые
* символы, отличные от ascii, через несколько кодировщиков Charset и выгрузить шестнадцатеричный код
* значения результирующих последовательностей байтов.
*
* @автор Рон Хитченс ([email protected])
*/
общественный класс EncodeTest {
public static void main(String[] argv) выдает исключение {
// Это последовательность символов для кодирования
Строковый ввод = "/u00bfMa/u00f1ana?";
// список кодировок для кодирования
String[] charsetNames = { "US-ASCII", "ISO-8859-1", "UTF-8",
"UTF-16BE", "UTF-16LE", "UTF-16" // , "X-ROT13"
};
for (int i = 0; я <charsetNames.length; i++) {
doEncode(Charset.forName(charsetNames[i]), input);
}
}
/**
* Для заданного набора символов и входной строки закодируйте символы и распечатайте
* кодировка результирующего байта в читаемом виде.
*/
Private static void doEncode(Charset cs, String input) {
ByteBuffer bb = cs.encode(вход);
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;
// Сохраняем красивое выравнивание таблицы
если (я < 10)
System.out.print(" ");
//Распечатать индексный номер
System.out.print(" " + i + ": ");
// Когда-нибудь появится лучший форматированный вывод...
если (ивал < 16)
System.out.print("0");
// Распечатываем шестнадцатеричное значение байта
System.out.print(Integer.toHexString(ival));
// Если байт кажется значением
// печатный символ, напечатайте его. Нет гарантии.
// это будет.
if (Character.isWhitespace(c) || Character.isISOControl(c)) {
System.out.println("");
} еще {
System.out.println(" (" + c + ")");
}
}
System.out.println("");
}
}
Кодировка: ISO-8859-1
Ввод: ?Ма?ана?
Закодировано:
0:20
1: парень (?)
2:4д (М)
3:61(а)
4: f1 (?)
5:61(а)
6: 6е(н)
7:61(а)
8:3ф (?)
Кодировка: UTF-8
Ввод: ?Ма?ана?
Закодировано:
0:20
1: с2 (?)
2: парень (?)
3:4д (М)
4:61(а)
5: с3 (?)
6: б1 (±)
7:61(а)
8:6е(н)
9:61(а)
10:3ф (?)
Кодировка: UTF-16BE.
Ввод: ?Ма?ана?
Закодировано:
0:00
1:20
2:00
3: парень (?)
4:00
5:4д (М)
6:00
7:61(а)
8:00
9: f1 (?)
10:00
11:61(а)
12:00
13:6е(н)
14:00
15:61(а)
16:00
17:3ф (?)
Кодировка: UTF-16LE.
Ввод: ?Ма?ана?
Закодировано:
0:20
1:00
2: парень (?)
3:00
4:4д (М)
5:00
6:61(а)
7:00
8: f1 (?)
9:00
10:61(а)
11:00
12:6е(н)
13:00
14:61(а)
15:00
16:3ф (?)
17:00
Кодировка: UTF-16
Ввод: ?Ма?ана?
Закодировано:
0: фе (?)
1: фф (?)
2:00
3:20
4:00
5: парень (?)
6:00
7:4д (М)
8:00
9:61(а)
10:00
11: f1 (?)
12:00
13:61(а)
14:00
15:6е(н)
16:00
17:61(а)
18:00
19:3ф (?)
пакет java.nio.charset;
публичный абстрактный класс Charset реализует Comparable
{
общедоступное статическое логическое значение isSupported (String charsetName)
общедоступный статический набор символов для имени (String charsetName)
общедоступная статическая SortedMap доступнаяCharsets()
публичное окончательное имя строки()
публичный финал Установить псевдонимы()
публичная строка displayName()
public String displayName (локаль)
публичное финальное логическое значение isRegistered()
общедоступное логическое значение canEncode()
публичный абстрактный CharsetEncoder newEncoder();
публичный окончательный код ByteBuffer (CharBuffer cb)
общедоступный окончательный код ByteBuffer (String str)
публичный абстрактный CharsetDecoder newDecoder();
публичное окончательное декодирование CharBuffer (ByteBuffer bb)
общедоступное абстрактное логическое значение содержит (Charset cs);
публичное окончательное логическое значение равно (Объект ob)
public Final int CompareTo (Объект ob)
публичный финал int hashCode()
публичная финальная строка toString()
}
В большинстве случаев на эти правила обращают внимание только продавцы JVM. Однако если вы планируете использовать в своем приложении собственный набор символов, будет полезно знать, чего не следует делать. Вы должны вернуть false для isRegistered() и назвать свой набор символов, начиная с «X -».
Сравнение набора символов:
публичный абстрактный класс Charset реализует Comparable
{
// Это частичный список API
общедоступное абстрактное логическое значение содержит (Charset cs);
публичное окончательное логическое значение равно (Объект ob)
public Final int CompareTo (Объект ob)
публичный финал int hashCode()
публичная финальная строка toString()
}
Кодер набора символов: набор символов состоит из закодированного набора символов и связанной схемы кодирования. Классы CharsetEncoder и CharsetDecoder реализуют схемы преобразования.
Одно замечание по поводу API CharsetEncoder: во-первых, чем проще форма encode(), тем она удобнее. Кодировка CharBuffer, которую вы предоставляете в перераспределенном ByteBuffer, объединяет все кодировки. Это последний метод, вызываемый при вызове encode() непосредственно в классе Charset.
Нижнее переполнение
Переполнение
Неверный ввод
Неотображаемый персонаж
Если во время кодирования кодировщик обнаруживает дефектный или несопоставляемый ввод, возвращается объект результата. Вы также можете протестировать отдельные символы или последовательности символов, чтобы определить, можно ли их закодировать. Вот как проверить, возможно ли кодирование:
пакет java.nio.charset;
общедоступный абстрактный класс CharsetEncoder
{
// Это частичный список API
общедоступное логическое значение canEncode (char c)
общедоступное логическое значение canEncode (CharSequence cs)
}
ОТЧЕТ
Поведение по умолчанию при создании CharsetEncoder. Такое поведение указывает на то, что об ошибках кодирования следует сообщать путем возврата объекта CoderResult, упомянутого ранее.
ИГНОРИРОВАТЬ (игнорировать)
Указывает, что ошибки кодирования следует игнорировать, а любой неправильный ввод должен быть прерван, если он находится вне позиции.
ЗАМЕНЯТЬ
Ошибки кодирования обрабатываются путем прерывания ввода ошибки и вывода текущей последовательности байтов замены, определенной для этого CharsetEncoder.
Помните, что кодирование набора символов преобразует символы в последовательность байтов для подготовки к дальнейшему декодированию. Если последовательность замены не может быть декодирована в действительную последовательность символов, закодированная последовательность байтов становится недействительной.
Класс CoderResult: объекты CoderResult возвращаются объектами CharsetEncoder и CharsetDecoder:
пакет java.nio.charset;
общественный класс CoderResult {
публичный статический окончательный CoderResult OVERFLOW
публичный статический окончательный CoderResult UNDERFLOW
публичное логическое значение isUnderflow()
общедоступное логическое значение isOverflow()
<span style="white-space:pre"> </span>публичное логическое значение isError()
публичное логическое значение isMalformed()
общедоступное логическое значение isUnmappable()
публичная длина int()
public static CoderResultmalformedForLength (длина int)
public static CoderResult unmappableForLength (длина int)
<span style="white-space:pre"> </span>public void throwException() генерирует исключение CharacterCodingException
}
пакет java.nio.charset;
общедоступный абстрактный класс CharsetDecoder
{
// Это частичный список API
публичный окончательный сброс CharsetDecoder()
публичное окончательное декодирование CharBuffer (вход ByteBuffer)
выдает исключение CharacterCodingException
общедоступное окончательное декодирование CoderResult (вход ByteBuffer, выход CharBuffer,
логическое значение endOfInput)
публичный окончательный сброс CoderResult (выход CharBuffer)
}
1. Сбросьте декодер, вызвав функцию сброса(), чтобы перевести декодер в известное состояние, готовое к приему входных данных.
2. Установите для endOfInput значение false и не вызывайте и не вызывайте decode() несколько раз для передачи байтов механизму декодирования. По мере продолжения декодирования символы будут добавляться в данный CharBuffer.
3. Установите для endOfInput значение true и один раз вызовите decode(), чтобы уведомить декодер о том, что все входные данные были предоставлены.
4. Вызовите методlush(), чтобы убедиться, что все декодированные символы отправлены на выход.
Пример 6-2 иллюстрирует, как кодировать поток байтов, представляющий кодировку набора символов.
Пример 6-2. Декодирование набора символов.
пакет com.ronsoft.books.nio.charset;
импортировать java.nio.*;
импортировать java.nio.charset.*;
импортировать java.nio.channels.*;
импортировать java.io.*;
/**
* Тестовое декодирование кодировки.
*
* @автор Рон Хитченс ([email protected])
*/
общественный класс CharsetDecode {
/**
* Тестовое декодирование кодировки в общем случае, обнаружение и обработка буфера
* переполнение/переполнение и сброс состояния декодера в конце ввода.
* читает со стандартного ввода и декодирует поток байтов в кодировке ASCII в символы.
* декодированные символы записываются в стандартный вывод. Это фактически «кот».
* вводить файлы ascii, но можно просто использовать другую кодировку
* указав его в командной строке.
*/
public static void main(String[] argv) выдает IOException {
// Кодировка по умолчанию — стандартная ASCII
Строка charsetName = "ISO-8859-1";
// Имя кодировки можно указать в командной строке
if (длина аргумента > 0) {
charsetName = argv[0];
}
// Обернуть канал вокруг стандартного ввода, обернуть канал вокруг стандартного вывода,
// находим названный набор символов и передаем его методу декодирования.
// Если указанная кодировка недействительна, создается исключение типа
// Будет создано исключение UnsupportedCharsetException.
decodeChannel(Channels.newChannel(System.in), новый OutputStreamWriter(
System.out), Charset.forName(charsetName));
}
/**
* Статический метод общего назначения, который считывает байты из канала, декодирует
* их согласно
*
* @param источник
* Объект ReadableByteChannel, который будет считан в EOF как
* источник закодированных байтов.
* @param писатель
* Объект Writer, в который будут записываться декодированные символы.
* Кодировка @param
* Объект Charset, чей CharsetDecoder будет использоваться для выполнения
* декодирование набора символов Java NIO 206.
*/
public static void decodeChannel (источник ReadableByteChannel, Writer Writer,
Кодировка набора символов) выдает UnsupportedCharsetException, IOException {
// Получаем экземпляр декодера из набора символов
Декодер 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 = ложь;
в то время как (!eof) {
// Опустошение входного буфера; декодеру требуется больше входных данных;
если (результат == CoderResult.UNDERFLOW) {
// декодер потребляет все входные данные, готовимся к пополнению
бб.очистить();
// Заполняем входной буфер; отслеживаем EOF;
eof = (source.read(bb) == -1);
// Подготавливаем буфер для чтения декодером
бб.флип();
}
// Декодируем входные байты для вывода символов, передаем флаг EOF;
результат = decoder.decode(bb, cb, eof);
// Если выходной буфер заполнен, сливаем вывод
если (результат == CoderResult.OVERFLOW) {
стокCharBuf (cb, писатель);
}
}
// Сбрасываем все оставшееся состояние из декодера, соблюдая осторожность
// для обнаружения переполнения выходного буфера
while (decoder.flush(cb) == CoderResult.OVERFLOW) {
стокCharBuf (cb, писатель);
}
// Очистка всех символов, оставшихся в выходном буфере
стокCharBuf (cb, писатель);
// Закрываем канал; выводим все буферизованные данные на стандартный вывод
источник.закрыть();
писатель.flush();
}
/**
* Вспомогательный метод для очистки буфера символов и записи его содержимого в заданный
* Объект Writer. По возвращении буфер пуст и готов к пополнению.
*
* @param cb
* CharBuffer, содержащий символы для записи.
* @param писатель
* Объект Writer для использования символов в cb.
*/
static void дренажCharBuf(CharBuffer cb, Writer Writer) выдает IOException {
cb.flip(); // Подготавливаем буфер к опорожнению
// Это записывает символы, содержащиеся в CharBuffer, но
// фактически не изменяет состояние буфера.
// Если буфер символов опустошался вызовами get(),
// здесь может понадобиться цикл.
если (cb.hasRemaining()) {
Writer.write(cb.toString());
}
cb.clear(); // Подготавливаем буфер для повторного заполнения
}
}
Прежде чем просматривать API, важно объяснить, как работает Charset SPI. Пакет java.nio.charset.spi содержит только один класс извлечения — CharsetProvider. Конкретные реализации этого класса предоставляют информацию, связанную с предоставляемыми ими объектами Charset. Чтобы определить собственный набор символов, необходимо сначала создать конкретные реализации Charset, CharsetEncoder и CharsetDecoder из пакета java.nio.charset. Затем вы создаете собственный подкласс CharsetProvider, который будет предоставлять эти классы JVM.
Создайте собственный набор символов:
Минимум, что вам нужно сделать, это создать подкласс java.nio.charset.Charset, предоставить конкретные реализации трех методов извлечения и конструктор. Класс Charset не имеет конструктора без параметров по умолчанию. Это означает, что ваш класс пользовательского набора символов должен иметь конструктор, даже если он не принимает параметры. Это связано с тем, что вы должны вызвать конструктор Charset во время создания экземпляра (путем вызова super() в начале вашего конструктора), таким образом предоставив ему имя и псевдоним спецификации вашего набора символов. Это позволит методам класса Charset обрабатывать за вас все, что связано с именем, и это хорошо.
Аналогичным образом вам необходимо предоставить конкретные реализации CharsetEncoder и CharsetDecoder. Напомним, что набор символов — это совокупность закодированных символов и схем кодирования/декодирования. Как мы видели ранее, кодирование и декодирование на уровне API практически симметричны. Здесь приводится краткое обсуждение того, что необходимо для реализации кодера: то же самое относится и к построению декодера.
Подобно Charset, CharsetEncoder не имеет конструктора по умолчанию, поэтому вам нужно вызвать super() в конструкторе конкретного класса, предоставив необходимые параметры.
Чтобы предоставить собственную реализацию CharsetEncoder, вы должны как минимум предоставить конкретный метод encodeLoop(). Для простых алгоритмов кодирования реализация других методов по умолчанию должна работать нормально. Обратите внимание, что encodeLoop() принимает параметры, аналогичные параметрам encode(), за исключением логического флага. Метод encode() представляет фактическое кодирование для encodeLoop(), которому нужно только обращать внимание на символы, потребляемые из параметра CharBuffer, и выводить закодированные байты в предоставленный ByteBuffer.
Теперь, когда мы увидели, как реализовать пользовательские наборы символов, включая соответствующие кодеры и декодеры, давайте посмотрим, как подключить их к JVM, чтобы мы могли запускать код с их использованием.
Укажите свой собственный набор символов:
Чтобы предоставить собственную реализацию Charset для среды выполнения JVM, вы должны создать конкретные подклассы класса CharsetProvider в java.nio.charsets.-spi, каждый из которых имеет конструктор без параметров. Конструктор без параметров важен, поскольку ваш класс CharsetProvider будет найден путем чтения полного имени файла конфигурации. Эта строка имени класса затем будет импортирована в Class.newInstance() для создания экземпляра вашего провайдера, который работает только через конструктор без параметров.
Файл конфигурации, считываемый JVM, находит поставщика набора символов с именем java.nio.charset.spi.CharsetProvider. Он расположен в исходном каталоге (META-INF/services) в пути к классам JVM. Каждый JavaArchive (JAR) имеет каталог META-INF, содержащий информацию о классах и ресурсах в этом JAR. Каталог с именем META-INF также можно разместить вверху обычных каталогов в пути к классам JVM.
API CharsetProvider практически бесполезен. Фактическая работа по предоставлению пользовательского набора символов происходит при создании пользовательских классов Charset, CharsetEncoder и CharsetDecoder. CharsetProvider — это просто посредник между вашим набором символов и средой выполнения.
В примере 6-3 демонстрируется реализация пользовательского набора символов и CharsetProvider, включая код выборки, который иллюстрирует использование набора символов, кодирование и декодирование, а также Charset SPI. В примере 6-3 реализован собственный набор символов.
Пример 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, является кодировкой Rot-13.
* простой алгоритм обфускации текста, который сдвигает алфавитные символы на 13
* так, чтобы «a» стало «n», «o» стало «b» и т. д. Этот алгоритм был популяризирован
* на дискуссионных форумах Usenet много лет назад, чтобы замаскировать неприличные слова, скрыть
* ответы на вопросы и т. д. Алгоритм Rot13 симметричен, применяется.
* текст, зашифрованный Rot13, даст вам оригинал
* расшифрованный текст.
*
* Применение этой кодировки Charset к выходному потоку приведет к тому, что все, что вы
* напишите в этот поток, чтобы Rot13 зашифровал его так, как написано, и применил.
* попадание во входной поток приводит к дескремблированию считываемых данных Rot13 по мере их чтения.
*
* @автор Рон Хитченс ([email protected])
*/
публичный класс Rot13Charset расширяет Charset {
// имя базовой кодировки, которой мы делегируем
частная статическая окончательная строка BASE_CHARSET_NAME = "UTF-8";
// Дескриптор реальной кодировки, которую мы будем использовать для перекодирования между
// символы и байты. Это позволит нам применить Rot13.
// алгоритм для многобайтовых кодировок Но только.
// Альфа-символы ASCII будут повернуты независимо от базовой кодировки.
Кодировка baseCharset;
/**
* Конструктор для набора символов Rot13. Вызов конструктора суперкласса.
* укажите имена, под которыми нас будут знать. Затем сохраните ссылку на файл.
* делегат Charset.
*/
protected Rot13Charset (строка каноническая, псевдонимы String []) {
супер(канонический, псевдонимы);
// Сохраняем базовую кодировку, которую мы делегируем
baseCharset = Charset.forName(BASE_CHARSET_NAME);
}
//------------------------------------------------ ----------
/**
* Вызывается пользователями этого набора символов для получения кодировщика.
* создает экземпляр частного класса (определенного ниже) и передает его
* кодировщик из базовой кодировки.
*/
общественный CharsetEncoder newEncoder() {
вернуть новый Rot13Encoder(this, baseCharset.newEncoder());
}
/**
* Вызывается пользователями этой кодировки для получения декодера.
* создает экземпляр частного класса (определенного ниже) и передает его
* декодер из базовой Charset.
*/
общественный CharsetDecoder newDecoder() {
вернуть новый Rot13Decoder(this, baseCharset.newDecoder());
}
/**
* Этот метод должен быть реализован с помощью конкретных кодировок. Мы всегда говорим «нет».
* что безопасно.
*/
public boolean contains(Charset cs) {
возврат (ложь);
}
/**
* Общая процедура поворота всех альфа-символов ASCII в заданном
* CharBuffer на 13. Обратите внимание, что этот код явно сравнивает верхние и
* символы ASCII нижнего регистра вместо использования методов
* Character.isLowerCase и Character.isUpperCase. Это связано с тем, что.
* схема поворота на 13 корректно работает только для буквенных символов
* кодировка ASCII и эти методы могут возвращать true для Юникода, отличного от ASCII.
* символы.
*/
частный недействительный rot13 (CharBuffer cb) {
for (int pos = cb.position(); pos < cb.limit(); pos++) {
символ c = cb.get(pos);
символ а = '/u0000';
// Это строчная альфа?
if ((c >= 'a') && (c <= 'z')) {
а = 'а';
}
// Это буква в верхнем регистре?
if ((c >= 'A') && (c <= 'Z')) {
а = 'А';
}
// Если да, то катим на 13
если (а != '/u0000') {
c = (char) ((((c - a) + 13) % 26) + a);
cb.put(pos, c);
}
}
}
//------------------------------------------------ --------
/**
* Реализация кодировщика для Rot13 Chars et.
* соответствующий класс декодера, указанный ниже, также должен переопределить методы "impl",
* например, implOnMalformedInput() и выполнять сквозные вызовы
* Объект baseEncoder. Это оставлено в качестве упражнения для хакера.
*/
частный класс Rot13Encoder расширяет CharsetEncoder {
частный базовый кодировщик CharsetEncoder;
/**
* Конструктор, вызов конструктора суперкласса с объектом Charset.
* и размеры кодировок из кодировщика делегата.
*/
Rot13Encoder(Charset cs, CharsetEncoder baseEncoder) {
супер(cs, baseEncoder.averageBytesPerChar(), baseEncoder
.maxBytesPerChar());
this.baseEncoder = baseEncoder;
}
/**
* Реализация цикла кодирования Сначала применяем Rot13.
* алгоритм скремблирования в CharBuffer, затем сбросить кодировщик для
* базовый набор символов и вызовите его метод encode() для выполнения фактического действия.
* кодировка. Это может работать неправильно для нелатинских кодировок.
* Передаваемый CharBuffer может быть доступен только для чтения или повторно использован вызывающей стороной для
* для других целей, поэтому дублируем его и применяем кодировку Rot13 к
* copy. Мы ДЕЙСТВИТЕЛЬНО хотим переместить позицию входного буфера на
* отражают израсходованные символы.
*/
protected CoderResult encodeLoop (CharBuffer cb, ByteBuffer bb) {
CharBuffer tmpcb = CharBuffer.allocate(cb.remaining());
в то время как (cb.hasRemaining()) {
tmpcb.put(cb.get());
}
tmpcb.перемотка();
rot13(tmpcb);
baseEncoder.reset();
CoderResult cr = baseEncoder.encode(tmpcb, bb, true);
// Если ошибка или выход переполнился, нам нужно отрегулировать
// позиция входного буфера, соответствующая тому, что
// действительно был использован из временного буфера If.
// опустошение (все входные данные израсходованы), это пустая операция.
cb.position(cb.position() - tmpcb.remaining());
возврат (кр);
}
}
//------------------------------------------------ --------
/**
* Реализация декодера для набора символов Rot13.
*/
частный класс Rot13Decoder расширяет CharsetDecoder {
частный базовый декодер CharsetDecoder;
/**
* Конструктор, вызов конструктора суперкласса с объектом Charset.
* и передать значения символов/байтов из декодера делегата.
*/
Rot13Decoder (Charset cs, CharsetDecoder baseDecoder) {
супер(cs, baseDecoder.averageCharsPerByte(), baseDecoder
.maxCharsPerByte());
this.baseDecoder = baseDecoder;
}
/**
* Реализация цикла декодирования Сначала мы сбрасываем декодер.
* базовую кодировку, затем вызовите ее для декодирования байтов в символы,
* сохранение результирующего кода. Затем CharBuffer дескремблируется с помощью
* Алгоритм Rot13 и возвращается код результата. Это может не работать.
* правильно для нелатинских кодировок.
*/
protected CoderResult decodeLoop (ByteBuffer bb, CharBuffer cb) {
baseDecoder.reset();
Coderresult result = basedecoder.decode (bb, cb, true);
ROT13 (CB);
возврат (результат);
}
}
// ------------------------------------------------ --------
/**
* Единый тест для rot13 charset.
* файл, если указано в командной строке, или stdin, если не предоставлены аргументы, и
* Напишите содержимое в STDOUT через кодирование x -rot13
* «Шифрование», реализованное алгоритмом ROT13, является симметричным
* в простого текстовом файле, например, исходный код Java, выведет
* Версия.
* Оригинальный текстовый документ.
*/
public static void main (string [] argv) бросает исключение {
BufferedReader In;
if (argv. Length> 0) {
// Откройте указанный файл
in = new BufferedReader (новый FileReader (argv [0]));
} еще {
// Обернуть буферный читатель вокруг Stdin
in = new BufferedReader (новый inputStreamReader (System.in));
}
// Создать PrintStream, который использует кодирование ROT13
Printsstream out = new PrintStream (System.out, false, "x -Rot13");
Строка с = ноль;
// Читать все ввод и написать его на вывод.
// как данные проходят через PrintStream,
// это будет гнить13-кодировку.
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, который предоставляет charsets, предоставленные
* Ronsoft
* Не зарегистрированная Яна Чарсет, поэтому его имя начинается с «X-», чтобы избежать имени
* столкновения с официальными чарсами.
*
* Чтобы активировать этот charsetProvider, необходимо добавить файл в
* Палата класса среды выполнения JVM в следующем месте:
* Meta-Inf/Services/java.nio.charsets.spi.charsetProvider
*
* Этот файл должен содержать строку с полностью квалифицированным именем этого класса на
* Страна само по себе: com.ronsoft.books.nio.charset.ronsoftcharsetProvider Java
* Nio 216
*
* Смотрите страницу Javadoc для java.nio.charsets.spi.charsetProvider для полного
* подробности.
*
* @author Ron Hitchens ([email protected])
*/
открытый класс RonsoftcharetProvider Extends CharsetProvider {
// название Чарсета, которое мы предоставляем
частная статическая конечная строка charset_name = "x-dot13";
// ручка к объекту Charset
Частный charset rot13 = null;
/**
* Конструктор, создайте экземпляр объекта Charset и сохраните ссылку.
*/
public ronsoftcharsetProvider () {
this.rot13 = new rot13charset (charset_name, new String [0]);
}
/**
* Вызван статическими методами Charset, чтобы найти конкретный названный Charset
* Это имя этого чарсета (у нас нет псевдонимов), затем верните
* Rot13 charset, else return null.
*/
public charsetforname (string charsetname) {
if (charsetname.equalsignorecase (charset_name)) {
возврат (ROT13);
}
возврат (null);
}
/**
* Верните итератор по набору объектов Charset, которые мы предоставляем.
*
* @return Объект итератора, содержащий ссылки на все чарсеты
* Объекты, предоставленные этим классом.
*/
public iterator <charset> charsets () {
Hashset <charset> set = new Hashset <CHARSET> (1);
set.add (rot13);
return (set.iterator ());
}
}
Добавление x -Rot13 в список набора символов в примере 6-1 создает этот дополнительный вывод:
Charset: рентген
Вход: żmaana?
Кодировано:
0: C2 (ż)
1: bf (ż)
2: 5a (z)
3: 6e (n)
4: C3 (ă)
5: B1 (±)
6: 6e (n)
7:61 (а)
8: 6e (n)
9: 3f (?)
Charset (класс набора символов)
Схема кодирования символов, которая инкапсулирует кодирование, используемое для представления последовательностей символов, которые отличаются от набора символов как последовательность байтов.
Charsetencoder (класс кодирования символов)
Кодирование двигателя преобразует последовательности символов в байтовые последовательности. Затем последовательность байтов может быть декодирована для реконструкции последовательности символов исходной.
Charsetdecoder (класс декодера Charset)
Двигатель декодирования преобразует кодированную последовательность байтов в последовательность символов.
Charsetprovider spi (charset provier spi)
Найдите и сделайте реализацию Charset доступной через механизм поставщика сервера для использования в среде времени выполнения.