Bases du jeu de caractères :
Jeu de caractères
Une collection de caractères, c'est-à-dire des symboles dotés d'une sémantique particulière. La lettre "A" est un caractère. "%" est aussi un caractère. Il n'a aucune valeur numérique intrinsèque et n'a aucune connexion directe avec ASC II, Unicode ou même des ordinateurs. Les symboles existaient bien avant les ordinateurs.
Jeu de caractères codés
Une valeur numérique est attribuée à une collection de caractères. Attribuez des codes aux caractères afin qu'ils puissent exprimer des résultats numériques à l'aide d'un jeu de codage de caractères spécifique. D'autres jeux de caractères codés peuvent attribuer des valeurs différentes au même caractère. Les mappages de jeux de caractères sont généralement déterminés par des organismes de normalisation, tels que USASCII, ISO 8859-1, Unicode (ISO 10646-1) et JIS X0201.
Schéma de codage des caractères
Mappage des membres du jeu de caractères codés en octets (octets de 8 bits). Un schéma de codage définit la manière dont une séquence de codages de caractères est exprimée sous forme de séquence d'octets. Il n'est pas nécessaire que la valeur du codage des caractères soit la même que celle de l'octet de codage, ni qu'il s'agisse d'une relation un-à-un ou un-à-plusieurs. En principe, le codage et le décodage des jeux de caractères peuvent être assimilés à la sérialisation et à la désérialisation d'objets.
Habituellement, le codage des données de caractères est utilisé pour la transmission réseau ou le stockage de fichiers. Un schéma de codage n'est pas un jeu de caractères, c'est un mappage ; mais en raison de leur relation étroite, la plupart des codages sont associés à un jeu de caractères distinct. Par exemple, UTF-8,
Utilisé uniquement pour encoder les jeux de caractères Unicode. Néanmoins, il est possible d’utiliser un seul schéma de codage pour gérer plusieurs jeux de caractères. Par exemple, EUC peut coder des caractères pour plusieurs langues asiatiques.
La figure 6-1 est une expression graphique qui utilise le schéma de codage UTF-8 pour coder une séquence de caractères Unicode en séquence d'octets. UTF-8 encode les valeurs de code de caractères inférieures à 0x80 en une valeur sur un seul octet (standard ASC II). Tous les autres caractères Unicode sont codés sous forme de séquences multi-octets de 2 à 6 octets (http://www.ietf.org/rfc/rfc2279.txt).
Jeu de caractères
Le terme charset est défini dans la RFC2278 (http://ietf.org/rfc/rfc2278.txt). Il s'agit d'une collection de jeux de caractères codés et de schémas de codage de caractères. La classe du package java.nio.charset est Charset, qui encapsule l'extraction du jeu de caractères.
1111111111111111
Unicode est un codage de caractères sur 16 bits. Il tente d'unifier les jeux de caractères de toutes les langues du monde en une cartographie unique et complète. Il a gagné sa place, mais il existe aujourd’hui de nombreux autres codages de caractères largement utilisés.
La plupart des systèmes d'exploitation sont toujours orientés octets en termes d'E/S et de stockage de fichiers. Ainsi, quel que soit le codage utilisé, Unicode ou autre, il est toujours nécessaire d'effectuer une conversion entre les séquences d'octets et les codages de jeux de caractères.
Les classes composées du package java.nio.charset répondent à ce besoin. Ce n'est pas la première fois que la plate-forme Java s'attaque au codage des jeux de caractères, mais il s'agit de la solution la plus systématique, la plus complète et la plus flexible. Le package java.nio.charset.spi fournit une interface de provisionnement de serveur (SPI) afin que les encodeurs et les décodeurs puissent être branchés selon les besoins.
Jeu de caractères : la valeur par défaut est déterminée au démarrage de la JVM et dépend de l'environnement du système d'exploitation sous-jacent, des paramètres régionaux et/ou de la configuration de la JVM. Si vous avez besoin d’un jeu de caractères spécifique, le plus sûr est de le nommer explicitement. Ne présumez pas que le déploiement par défaut est le même que votre environnement de développement. Les noms de jeux de caractères ne sont pas sensibles à la casse, c'est-à-dire que les lettres majuscules et les lettres minuscules sont considérées comme identiques lors de la comparaison des noms de jeux de caractères. L'IANA (Internet Assigned Names Authority) conserve tous les noms de jeux de caractères officiellement enregistrés.
L'exemple 6-1 montre comment traduire des caractères en séquences d'octets en utilisant différentes implémentations de Charset.
Exemple 6-1. Utilisation du codage de jeu de caractères standard
paquet com.ronsoft.books.nio.charset ;
importer java.nio.charset.Charset ;
importer java.nio.ByteBuffer ;
/**
* Test d'encodage Charset Exécutez la même chaîne d'entrée, qui en contient.
* Caractères non-ASCII, via plusieurs encodeurs Charset et vidage de l'hexadécimal
* valeurs des séquences d'octets résultantes.
*
* @auteur Ron Hitchens ([email protected])
*/
classe publique EncodeTest {
public static void main(String[] argv) lève une exception {
// Voici la séquence de caractères à encoder
Entrée de chaîne = "/u00bfMa/u00f1ana ?";
// la liste des jeux de caractères avec lesquels encoder
String[] charsetNames = { "US-ASCII", "ISO-8859-1", "UTF-8",
"UTF-16BE", "UTF-16LE", "UTF-16" // , "X-ROT13"
} ;
pour (int i = 0; i < charsetNames.length; i++) {
doEncode(Charset.forName(charsetNames[i]), entrée);
}
}
/**
* Pour un jeu de caractères et une chaîne d'entrée donnés, encodez les caractères et imprimez le
* Codage d'octets résultant sous une forme lisible.
*/
private static void doEncode (Charset cs, entrée de chaîne) {
ByteBuffer bb = cs.encode(entrée);
System.out.println("Charset: " + cs.name());
System.out.println(" Entrée : " + entrée);
System.out.println("Encodé : ");
pour (int i = 0; bb.hasRemaining(); i++) {
int b = bb.get();
int ival = ((int) b) & 0xff;
char c = (char)ival;
// Gardez un joli alignement tabulaire
si (i < 10)
System.out.print(" ");
//Imprimer le numéro d'index
System.out.print(" " + i + ": ");
// Une sortie mieux formatée arrivera un jour...
si (val < 16)
System.out.print("0");
// Affiche la valeur hexadécimale de l'octet
System.out.print(Integer.toHexString(ival));
// Si l'octet semble être la valeur d'un
// caractère imprimable, imprimez-le Aucune garantie.
// ce sera.
if (Character.isWhitespace(c) || Character.isISOControl(c)) {
System.out.println("");
} autre {
System.out.println(" (" + c + ")");
}
}
System.out.println("");
}
}
Jeu de caractères : ISO-8859-1
Entrée : Ma ana ?
Codé :
0:20
1 : petit ami (?)
2 : 4j (M)
3:61(a)
4 : f1 (?)
5:61(a)
6 : 6e(n)
7:61(a)
8 : 3f (?)
Jeu de caractères : UTF-8
Entrée : Ma ana ?
Codé :
0:20
1 : c2 (?)
2 : petit ami (?)
3 : 4j (M)
4:61(a)
5 : c3 (?)
6 : b1 (±)
7:61(a)
8 : 6e(n)
9:61(a)
10h30 (?)
Jeu de caractères : UTF-16BE
Entrée : Ma ana ?
Codé :
0:00
1:20
14h00
3 : petit ami (?)
16h00
5 : 4j (M)
6h00
7:61(a)
8h00
9 : f1 (?)
10h00
11:61(a)
12h00
13 : 6e(n)
14h00
15 : 61 (a)
16h00
17 : 3f (?)
Jeu de caractères : UTF-16LE
Entrée : Ma ana ?
Codé :
0:20
1h00
2 : petit ami (?)
15h00
4 : 4j (M)
17h00
6:61(a)
7h00
8 : f1 (?)
9h00
10:61(a)
11h00
12 : 6e(n)
13h00
14 : 61 (a)
15h00
16 : 3f (?)
17h00
Jeu de caractères : UTF-16
Entrée : Ma ana ?
Codé :
0 : fé (?)
1 : ff (?)
14h00
15h20
16h00
5 : petit ami (?)
6h00
7 : 4j (M)
8h00
9:61(a)
10h00
11 : f1 (?)
12h00
13 : 61 (a)
14h00
15 : 6e(n)
16h00
17 : 61 (a)
18h00
19 : 3f (?)
paquet java.nio.charset ;
classe abstraite publique Charset implémente Comparable
{
public statique booléen isSupported (String charsetName)
Charset statique public pourName (String charsetName)
public statique SortedMap disponibleCharsets()
nom de chaîne final public ()
public final Définir les alias()
chaîne publique displayName()
public String displayName (Locale locale)
public final booléen isRegistered()
public booléen canEncode()
public abstrait CharsetEncoder newEncoder();
encodage public final ByteBuffer (CharBuffer cb)
encodage public final ByteBuffer (String str)
public abstrait CharsetDecoder newDecoder();
décodage public final de CharBuffer (ByteBuffer bb)
public abstract boolean contient (Charset cs);
public final booléen égal (Objet ob)
public final int compareTo (Objet ob)
public final int hashCode()
chaîne finale publique toString()
}
La plupart du temps, seuls les vendeurs de JVM prêtent attention à ces règles. Toutefois, si vous envisagez d'utiliser votre propre jeu de caractères dans le cadre de votre application, il sera utile de savoir ce qu'il ne faut pas faire. Vous devez renvoyer false pour isRegistered() et nommer votre jeu de caractères en commençant par "X -".
Comparaison des jeux de caractères :
classe abstraite publique Charset implémente Comparable
{
// Ceci est une liste partielle d'API
public abstract boolean contient (Charset cs);
public final booléen égal (Objet ob)
public final int compareTo (Objet ob)
public final int hashCode()
chaîne finale publique toString()
}
Encodeur de jeu de caractères : un jeu de caractères est composé d'un jeu de caractères codés et d'un schéma de codage associé. Les classes CharsetEncoder et CharsetDecoder implémentent des schémas de conversion.
Une remarque sur l'API CharsetEncoder : tout d'abord, plus la forme encode() est simple, plus elle est pratique. L'encodage du CharBuffer que vous fournissez dans le ByteBuffer réalloué combine tous les encodages. C'est la dernière méthode appelée lorsque vous appelez encode() directement sur la classe Charset.
Sous-versement
Débordement
Entrée mal formée
Caractère impossible à mapper
Lors du codage, si l'encodeur rencontre une entrée défectueuse ou non mappable, un objet résultat est renvoyé. Vous pouvez également tester des caractères individuels ou des séquences de caractères pour déterminer s'ils peuvent être codés. Voici comment vérifier si l'encodage est possible :
paquet java.nio.charset ;
classe abstraite publique CharsetEncoder
{
// Ceci est une liste partielle d'API
public booléen canEncode (char c)
canEncode booléen public (CharSequence cs)
}
RAPPORT
Comportement par défaut lors de la création d'un CharsetEncoder. Ce comportement indique que les erreurs de codage doivent être signalées en renvoyant l'objet CoderResult, mentionné précédemment.
IGNORER (ignorer)
Indique que les erreurs d'encodage doivent être ignorées et que toute entrée incorrecte doit être abandonnée si elle n'est pas positionnée.
REMPLACER
Les erreurs de codage sont gérées en abandonnant l'entrée de l'erreur et en produisant la séquence d'octets de remplacement actuelle définie pour ce CharsetEncoder.
N'oubliez pas que le codage par jeu de caractères convertit les caractères en une séquence d'octets en vue d'un décodage ultérieur. Si la séquence de remplacement ne peut pas être décodée en une séquence de caractères valide, la séquence d'octets codée devient invalide.
Classe CoderResult : les objets CoderResult sont renvoyés par les objets CharsetEncoder et CharsetDecoder :
paquet java.nio.charset ;
classe publique CoderResult {
public statique final CoderResult OVERFLOW
CoderResult final statique public UNDERFLOW
public booléen isUnderflow()
public booléen isOverflow()
<span style="white-space:pre"> </span>booléen public isError()
public booléen isMalformed()
public booléen isUnmappable()
public int longueur()
CoderResult statique public malformedForLength (longueur int)
coderResult statique public unmappableForLength (longueur int)
<span style="white-space:pre"> </span>public void throwException() lance CharacterCodingException
}
paquet java.nio.charset ;
classe abstraite publique CharsetDecoder
{
// Ceci est une liste partielle d'API
réinitialisation publique finale du CharsetDecoder ()
décodage public final du CharBuffer (ByteBuffer in)
lance CharacterCodingException
décodage public final de CoderResult (ByteBuffer in, CharBuffer out,
booléen endOfInput)
vidage final public de CoderResult (CharBuffer out)
}
1. Réinitialisez le décodeur en appelant reset() pour mettre le décodeur dans un état connu, prêt à recevoir une entrée.
2. Définissez endOfInput sur false et n'appelez pas ou n'appelez pas decode() plusieurs fois pour fournir des octets au moteur de décodage. Au fur et à mesure du décodage, des caractères seront ajoutés au CharBuffer donné.
3. Définissez endOfInput sur true et appelez decode() une fois pour informer le décodeur que toutes les entrées ont été fournies.
4. Appelez flush() pour vous assurer que tous les caractères décodés ont été envoyés à la sortie.
L'exemple 6-2 illustre comment coder un flux d'octets représentant un codage de jeu de caractères.
Exemple 6-2. Décodage du jeu de caractères
paquet com.ronsoft.books.nio.charset ;
importer java.nio.* ;
importer java.nio.charset.* ;
importer java.nio.channels.* ;
importer java.io.* ;
/**
* Testez le décodage du jeu de caractères.
*
* @auteur Ron Hitchens ([email protected])
*/
classe publique CharsetDecode {
/**
* Tester le décodage du jeu de caractères dans le cas général, détection et gestion du tampon
* sous/débordement et vidage de l'état du décodeur à la fin de l'entrée de ce code.
* lit depuis stdin et décode le flux d'octets codé en ASCII en caractères.
* Les caractères décodés sont écrits sur la sortie standard. Il s'agit en fait d'un "chat" pour.
* saisissez des fichiers ascii, mais un autre codage de jeu de caractères pourrait être utilisé simplement
* en le spécifiant sur la ligne de commande.
*/
public static void main(String[] argv) lance IOException {
// Le jeu de caractères par défaut est ASCII standard
Chaîne charsetName = "ISO-8859-1" ;
// Le nom du jeu de caractères peut être spécifié sur la ligne de commande
if (argv. longueur > 0) {
charsetName = argv[0];
}
// Enroulez un canal autour de stdin, enroulez un canal autour de stdout,
// trouve le Charset nommé et le transmet à la méthode deco de.
// Si le jeu de caractères nommé n'est pas valide, une exception de type
// UnsupportedCharsetException sera levée.
decodeChannel (Channels.newChannel (System.in), nouveau OutputStreamWriter (
System.out), Charset.forName(charsetName));
}
/**
* Méthode statique à usage général qui lit les octets d'un canal, décode
*les selon
*
* Source @param
* Un objet ReadableByteChannel qui sera lu dans EOF en tant que
* source des octets codés.
* @param écrivain
* Un objet Writer dans lequel les caractères décodés seront écrits.
* @param jeu de caractères
* Un objet Charset, dont CharsetDecoder sera utilisé pour effectuer le
* Décodage du jeu de caractères Java NIO 206.
*/
public static void decodeChannel (source ReadableByteChannel, écrivain Writer,
Charset charset) lance UnsupportedCharsetException, IOException {
// Récupère une instance de décodeur à partir du Charset
CharsetDecoder décodeur = charset.newDecoder();
// Dites au décodeur de remplacer les mauvais caractères par la marque par défaut
decoder.onMalformedInput(CodingErrorAction.REPLACE);
decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
// Alloue des tailles de tampon d'entrée et de sortie radicalement différentes
// à des fins de tests
ByteBuffer bb = ByteBuffer.allocateDirect(16 * 1024);
CharBuffer cb = CharBuffer.allocate(57);
// Le tampon commence vide ; indique qu'une entrée est nécessaire
Résultat CoderResult = CoderResult.UNDERFLOW ;
booléen eof = faux ;
tandis que (!eof) {
// Dépassement excessif du tampon d'entrée ; le décodeur veut plus d'entrées.
si (résultat == CoderResult.UNDERFLOW) {
// le décodeur consomme toutes les entrées, préparez-vous à recharger
bb.clear();
// Remplit le tampon d'entrée ; surveille EOF
eof = (source.read(bb) == -1);
// Prépare le buffer pour la lecture par le décodeur
bb.flip();
}
// Décode les octets d'entrée en caractères de sortie ; passe l'indicateur EOF
résultat = décodeur.decode(bb, cb, eof);
// Si le tampon de sortie est plein, draine la sortie
si (résultat == CoderResult.OVERFLOW) {
drainCharBuf(cb, écrivain);
}
}
// Vide tout état restant du décodeur, en faisant attention
// pour détecter les dépassements de tampon de sortie
while (decoder.flush(cb) == CoderResult.OVERFLOW) {
drainCharBuf(cb, écrivain);
}
// Vide tous les caractères restants dans le tampon de sortie
drainCharBuf(cb, écrivain);
// Ferme le canal ; envoie toutes les données mises en mémoire tampon vers la sortie standard.
source.close();
écrivain.flush();
}
/**
* Méthode d'assistance pour vider le tampon de caractères et écrire son contenu dans le fichier donné
* Objet Writer Au retour, le tampon est vide et prêt à être rempli.
*
* @paramcb
* Un CharBuffer contenant des caractères à écrire.
* @param écrivain
* Un objet Writer pour consommer les caractères dans cb.
*/
static void drainCharBuf (CharBuffer cb, Writer Writer) lance IOException {
cb.flip(); // Préparer le tampon pour le drainage
// Ceci écrit les caractères contenus dans le CharBuffer mais
// ne modifie pas réellement l'état du tampon.
// Si le tampon de caractères était vidé par les appels à get( ),
// une boucle pourrait être nécessaire ici.
si (cb.hasRemaining()) {
écrivain.write(cb.toString());
}
cb.clear(); // Prépare le tampon à remplir à nouveau
}
}
Avant de parcourir l'API, il est important d'expliquer le fonctionnement du Charset SPI. Le package java.nio.charset.spi ne contient qu'une seule classe d'extraction, CharsetProvider. Les implémentations concrètes de cette classe fournissent des informations relatives aux objets Charset qu'elles fournissent. Afin de définir un jeu de caractères personnalisé, vous devez d'abord créer des implémentations spécifiques de Charset, CharsetEncoder et CharsetDecoder à partir du package java.nio.charset. Vous créez ensuite une sous-classe personnalisée de CharsetProvider qui fournira ces classes à la JVM.
Créez un jeu de caractères personnalisé :
Le moins que vous ayez à faire est de créer une sous-classe de java.nio.charset.Charset, de fournir des implémentations concrètes des trois méthodes d'extraction et un constructeur. La classe Charset n’a pas de constructeur par défaut sans paramètre. Cela signifie que votre classe de jeu de caractères personnalisé doit avoir un constructeur, même si elle n'accepte pas de paramètres. En effet, vous devez appeler le constructeur de Charset au moment de l'instanciation (en appelant super() au début de votre constructeur), en lui fournissant ainsi le nom et l'alias de votre spécification de jeu de caractères. Cela permet aux méthodes de la classe Charset de gérer les éléments liés au nom pour vous, c'est donc une bonne chose.
De même, vous devez fournir des implémentations concrètes de CharsetEncoder et CharsetDecoder. Rappelons qu'un jeu de caractères est un ensemble de caractères codés et de schémas de codage/décodage. Comme nous l’avons vu précédemment, l’encodage et le décodage sont quasiment symétriques au niveau de l’API. Une brève discussion de ce qui est nécessaire pour implémenter un encodeur est donnée ici : la même chose s'applique à la construction d'un décodeur.
Semblable à Charset, CharsetEncoder n'a pas de constructeur par défaut, vous devez donc appeler super() dans le constructeur de classe concrète, en fournissant les paramètres requis.
Afin de fournir votre propre implémentation de CharsetEncoder, vous devez au moins fournir la méthode concrète encodeLoop(). Pour les algorithmes de codage simples, l’implémentation par défaut d’autres méthodes devrait fonctionner correctement. Notez que encodeLoop() prend des paramètres similaires à ceux de encode(), à l'exclusion de l'indicateur booléen. La méthode encode() représente l'encodage réel vers encodeLoop(), qui doit uniquement prêter attention aux caractères consommés à partir du paramètre CharBuffer et afficher les octets codés dans le ByteBuffer fourni.
Maintenant que nous avons vu comment implémenter des jeux de caractères personnalisés, y compris les encodeurs et décodeurs associés, voyons comment les connecter à la JVM afin de pouvoir exécuter du code en les utilisant.
Fournissez votre jeu de caractères personnalisé :
Afin de fournir votre propre implémentation Charset à l'environnement d'exécution JVM, vous devez créer des sous-classes concrètes de la classe CharsetProvider dans java.nio.charsets.-spi, chacune avec un constructeur sans paramètre. Le constructeur sans paramètre est important car votre classe CharsetProvider sera localisée en lisant le nom complet du fichier de configuration. Cette chaîne de nom de classe sera ensuite importée dans Class.newInstance() pour instancier votre fournisseur, qui ne fonctionne que via le constructeur sans paramètre.
Le fichier de configuration lu par la JVM localise le fournisseur de jeu de caractères, nommé java.nio.charset.spi.CharsetProvider. Il se trouve dans le répertoire source (META-INF/services) dans le chemin de classe JVM. Chaque JavaArchive (JAR) possède un répertoire META-INF qui contient des informations sur les classes et les ressources de ce JAR. Un répertoire nommé META-INF peut également être placé en haut des répertoires normaux dans le chemin de classe JVM.
L'API CharsetProvider est presque inutile. Le travail réel consistant à fournir un jeu de caractères personnalisé se produit lors de la création de classes Charset, CharsetEncoder et CharsetDecoder personnalisées. Le CharsetProvider est simplement un facilitateur entre votre jeu de caractères et l'environnement d'exécution.
L'exemple 6-3 montre l'implémentation d'un Charset et d'un CharsetProvider personnalisés, y compris un code d'échantillonnage qui illustre l'utilisation du jeu de caractères, l'encodage et le décodage, ainsi que le Charset SPI. L'exemple 6-3 implémente un jeu de caractères personnalisé.
Exemple 6-3. Jeu de caractères Rot13 personnalisé
paquet com.ronsoft.books.nio.charset ;
importer java.nio.CharBuffer ;
importer java.nio.ByteBuffer ;
importer java.nio.charset.Charset ;
importer java.nio.charset.CharsetEncoder ;
importer java.nio.charset.CharsetDecoder ;
importer java.nio.charset.CoderResult ;
importer java.util.Map ;
importer java.util.Iterator ;
importer java.io.Writer ;
importer java.io.PrintStream ;
importer java.io.PrintWriter ;
importer java.io.OutputStreamWriter ;
importer java.io.BufferedReader ;
importer java.io.InputStreamReader ;
importer java.io.FileReader ;
/**
* Une implémentation de Charset qui effectue l'encodage Rot13 est un encodage Rot-13.
* algorithme simple d'obscurcissement du texte qui décale les caractères alphabétiques de 13
* pour que 'a' devienne 'n', 'o' devienne 'b', etc. Cet algorithme a été popularisé
* par les forums de discussion Usenet il y a de nombreuses années pour masquer les vilains mots, cacher
* réponses aux questions, etc. L'algorithme Rot13 est symétrique, s'appliquant.
* le texte brouillé par Rot13 vous donnera l'original
*texte non crypté.
*
* L'application de cet encodage Charset à un flux de sortie entraînera tout ce que vous
* écrivez sur ce flux pour que Rot13 soit brouillé tel qu'il est écrit et appliqué.
* L'envoi dans un flux d'entrée entraîne le déchiffrement Rot13 des données lues au fur et à mesure de leur lecture.
*
* @auteur Ron Hitchens ([email protected])
*/
la classe publique Rot13Charset étend Charset {
// le nom du codage de jeu de caractères de base auquel nous déléguons
Chaîne finale statique privée BASE_CHARSET_NAME = "UTF-8" ;
// Handle vers le vrai jeu de caractères que nous utiliserons pour le transcodage entre
// caractères et octets Faire cela nous permet d'appliquer le Rot13.
// algorithme pour les encodages de jeux de caractères multioctets Mais uniquement le.
// Les caractères alpha ASCII seront pivotés, quel que soit l'encodage de base.
Jeu de caractères baseCharset ;
/**
* Constructeur pour le jeu de caractères Rot13 Appelez le constructeur de superclasse pour.
* transmettez le(s) nom(s) sous lequel(s) nous serons connus. Enregistrez ensuite une référence au(x) nom(s) sous lequel(s) nous serons connus.
*délégué Charset.
*/
protected Rot13Charset (String canonique, String[] alias) {
super(canonique, alias);
// Enregistrez le jeu de caractères de base auquel nous déléguons
baseCharset = Charset.forName(BASE_CHARSET_NAME);
}
//------------------------------------------------ ----------
/**
* Appelé par les utilisateurs de ce Charset pour obtenir un encodeur cette implémentation.
* instancie une instance d'une classe privée (définie ci-dessous) et la transmet
* un encodeur du Charset de base.
*/
public CharsetEncoder newEncoder() {
return new Rot13Encoder(this, baseCharset.newEncoder());
}
/**
* Appelé par les utilisateurs de ce Charset pour obtenir un décodeur cette implémentation.
* instancie une instance d'une classe privée (définie ci-dessous) et la transmet
* un décodeur du Charset de base.
*/
public CharsetDecoder newDecoder() {
return new Rot13Decoder(this, baseCharset.newDecoder());
}
/**
* Cette méthode doit être implémentée par des Charsets concrets. Nous disons toujours non,
* ce qui est sûr.
*/
public boolean contient (Charset cs) {
retour (faux);
}
/**
* Routine commune pour faire pivoter tous les caractères alpha ASCII dans le format donné
* CharBuffer par 13. Notez que ce code compare explicitement les valeurs supérieures et supérieures.
* caractères ASCII minuscules plutôt que d'utiliser les méthodes
* Character.isLowerCase et Character.isUpperCase C'est parce que le
* Le système de rotation par 13 ne fonctionne correctement que pour les caractères alphabétiques de
* le jeu de caractères ASCII et ces méthodes peuvent renvoyer vrai pour Unicode non-ASCII
* caractères.
*/
private void rot13 (CharBuffer cb) {
pour (int pos = cb.position(); pos < cb.limit(); pos++) {
char c = cb.get(pos);
char a = '/u0000';
// Est-ce un alpha minuscule ?
si ((c >= 'a') && (c <= 'z')) {
une = 'une';
}
// Est-ce un alpha majuscule ?
si ((c >= 'A') && (c <= 'Z')) {
une = « A » ;
}
// Si c'est le cas, lancez-le de 13
si (a != '/u0000') {
c = (caractère) ((((c - a) + 13) % 26) + a);
cb.put(pos, c);
}
}
}
//------------------------------------------------ ---------
/**
* L'implémentation de l'encodeur pour Rot13 Chars et cette classe, et le
* La classe de décodeur correspondante ci-dessous doit également remplacer les méthodes "impl",
* comme implOnMalformedInput( ) et effectuez des appels relais au
* Objet baseEncoder. Cela reste un exercice pour le pirate informatique.
*/
la classe privée Rot13Encoder étend CharsetEncoder {
baseEncoder CharsetEncoder privé ;
/**
* Constructeur, appelez le constructeur de superclasse avec l'objet Charset
* et les tailles d'encodages de l'encodeur délégué.
*/
Rot13Encoder (Charset cs, CharsetEncoder baseEncoder) {
super(cs, baseEncoder.averageBytesPerChar(), baseEncoder
.maxBytesPerChar());
this.baseEncoder = baseEncoder;
}
/**
* Implémentation de la boucle d'encodage. Tout d'abord, nous appliquons le Rot13.
* algorithme de brouillage vers le CharBuffer, puis réinitialisez l'encodeur pour
* le jeu de caractères de base et appelez sa méthode encode() pour effectuer le véritable
* encodage Cela peut ne pas fonctionner correctement pour les jeux de caractères non latins.
* CharBuffer transmis peut être en lecture seule ou réutilisé par l'appelant pour
* à d'autres fins, nous le dupliquons et appliquons l'encodage Rot13 au
* copie Nous voulons avancer la position du tampon d'entrée à.
* reflètent les caractères consommés.
*/
CoderResult protégé encodeLoop (CharBuffer cb, ByteBuffer bb) {
CharBuffer tmpcb = CharBuffer.allocate(cb.remaining());
tandis que (cb.hasRemaining()) {
tmpcb.put(cb.get());
}
tmpcb.rewind();
rot13(tmpcb);
baseEncoder.reset();
CoderResult cr = baseEncoder.encode(tmpcb, bb, true);
// En cas d'erreur ou de débordement de sortie, nous devons ajuster
// la position du tampon d'entrée pour correspondre à quoi
// a vraiment été consommé à partir du tampon temporaire.
// underflow (toutes les entrées consommées), c'est un non-op.
cb.position(cb.position() - tmpcb.remaining());
return(cr);
}
}
//------------------------------------------------ ---------
/**
* L'implémentation du décodeur pour le jeu de caractères Rot13.
*/
la classe privée Rot13Decoder étend CharsetDecoder {
baseDecoder CharsetDecoder privé ;
/**
* Constructeur, appelez le constructeur de superclasse avec l'objet Charset
* et transmettez les valeurs caractères/octets du décodeur délégué.
*/
Rot13Decoder (Charset cs, CharsetDecoder baseDecoder) {
super(cs, baseDecoder.averageCharsPerByte(), baseDecoder
.maxCharsPerByte());
this.baseDecoder = baseDecoder;
}
/**
* Implémentation de la boucle de décodage Tout d'abord, nous réinitialisons le décodeur pour.
* le jeu de caractères de base, puis appelez-le pour décoder les octets en caractères,
* sauvegarde du code résultat Le CharBuffer est ensuite décrypté avec le
* L'algorithme Rot13 et le code de résultat sont renvoyés. Cela peut ne pas fonctionner.
* correctement pour les jeux de caractères non latins.
*/
protégé CoderResult decodeLoop (ByteBuffer bb, CharBuffer cb) {
baseDecoder.reset();
Résultat CoderResult = baseDecoder.decode(bb, cb, true);
ROT13 (CB);
retour (résultat);
}
}
// ------------------------------------------------ ---------
/**
* Test unitaire pour le Charset ROT13.
* Fichier s'il est nommé sur la ligne de commande, ou stdin si aucun args n'est fourni, et
* Écrivez le contenu à STDOUT via le codage du charset X -ROT13.
* "Encryption" implémenté par l'algorithme ROT13 est symétrique.
* Dans un fichier de texte clair, tel que le code source Java par exemple, publiera un
* Version brouillée.
* Document de texte brut original.
*/
public static void main (String [] argv) lance une exception {
BufferedReader dans;
if (argv. longueur> 0) {
// Ouvrez le fichier nommé
dans = new BufferedReader (nouveau FileReader (argv [0]));
} autre {
// enveloppe un BufferedReader autour de stdin
dans = new BufferedReader (new inputStreamReader (System.in));
}
// Créer un PrintStream qui utilise le codage ROT13
PrintStream out = new printStream (System.out, false, "x -rot13");
Chaîne s = nulle ;
// Lisez toutes les entrées et écrivez-la dans la sortie.
// au fur et à mesure que les données passent par le PrintStream,
// Ce sera encodé de ROT13.
while ((s = in.readline ())! = null) {
out.println (s);
}
out.flush();
}
}
Exemple 6-4.
package com.ronsoft.books.nio.charset;
import java.nio.charse.Charset;
import java.nio.charset.spi.charsetProvider;
importer java.util.HashSet ;
Importer java.util.iterator;
/**
* Une classe CharsetProvider qui rend disponible lessets fournis par
* Ronsoft.
* Pas un Charset Iana enregistré, donc son nom commence par "x-" pour éviter le nom
* se heurte à des caractères officiels.
*
* Pour activer ce charsetprovider, il est nécessaire d'ajouter un fichier au
* CLASSPATH de l'exécution JVM à l'emplacement suivant:
* Meta-Inf / Services / Java.nio.Charsets.spi.CharsetProvider
*
* Ce fichier doit contenir une ligne avec le nom entièrement qualifié de cette classe sur
* Une ligne en soi: com.ronsoft.books.nio.charse.RonsoftCharsetProvider Java
* Nio 216
*
* Voir la page Javadoc pour java.nio.charsets.spi.charsetprovider pour complet
* détails.
*
* @author Ron Hitchens ([email protected])
*/
classe publique RonsoftCharsetProvider étend CharsetProvider {
// le nom du charme que nous fournissons
chaîne finale statique privée charset_name = "x-rot13";
// une poignée de l'objet Charset
Charset privé Rot13 = null;
/**
* Constructeur, instanciez un objet de charme et enregistrez la référence.
*/
public ronsoftcharsetprovider () {
this.rot13 = new rot13Charset (charset_name, new String [0]);
}
/**
* Appelé par les méthodes statiques de Charset pour trouver un charme nommé particulier.
* C'est le nom de ce charet (nous n'avons pas d'alias) puis renvoie le
* Charset ROT13, else retourne null.
*/
public Charset charSetForname (String charSetName) {
if (charSetName.equalSignoreCase (charset_name)) {
retour (rot13);
}
retour (null);
}
/**
* Renvoyez un itérateur sur l'ensemble des objets de charme que nous fournissons.
*
* @return un objet Iterator contenant des références à tout le charme
* Objets fournis par cette classe.
*/
Iterator public <Charset> Charsets () {
HashSet <Sharset> set = new Hashset <Charset> (1);
set.add (rot13);
return (set.iterator ());
}
}
L'ajout de x -rot13 à la liste des jeux de caractères dans l'exemple 6-1 produit cette sortie supplémentaire:
Charset: X-Rot13
Entrée: żmaana?
Encodé:
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 (classe de caractères)
Un schéma de codage de caractères qui résume le codage utilisé pour représenter des séquences de caractères différentes du jeu de caractères comme une séquence d'octets.
Charsetencoder (classe de codage des jeux de caractères)
Encoding Engine convertit les séquences de caractères en séquences d'octets. La séquence d'octets peut ensuite être décodée pour reconstruire la séquence de caractères source.
Charsetdecoder (classe Charset Decoder)
Le moteur de décodage convertit la séquence d'octets codés en séquence de caractères.
Charsetprovider SPI (Charset Provider SPI)
Localisez et mettez l'implémentation de Charset disponible via le mécanisme du fournisseur de serveur à utiliser dans l'environnement d'exécution.