Encoder la chaîne en UTF-8

190

J'ai une chaîne avec un caractère "ñ" et j'ai quelques problèmes avec elle. J'ai besoin d'encoder cette chaîne en encodage UTF-8. Je l'ai essayé de cette façon, mais cela ne fonctionne pas:

byte ptext[] = myString.getBytes();
String value = new String(ptext, "UTF-8");

Comment encoder cette chaîne en utf-8?

Alex
la source
2
On ne sait pas exactement ce que vous essayez de faire. MyString contient-il correctement le caractère ñ et vous avez des problèmes pour le convertir en un tableau d'octets (dans ce cas, voir les réponses de Peter et Amir), ou myString est-il corrompu et vous essayez de le réparer (dans ce cas, voir les réponses de Joachim et moi)?
Michael Borgwardt
J'ai besoin d'envoyer myString à un serveur avec un encodage utf-8 et j'ai besoin de convertir le caractère "ñ" en encodage utf-8.
Alex
1
Eh bien, si ce serveur attend UTF-8, ce que vous devez envoyer, ce sont des octets, pas une chaîne. Donc, selon la réponse de Peter, spécifiez le codage dans la première ligne et supprimez la deuxième ligne.
Michael Borgwardt
@Michael: Je suis d'accord sur le fait que l'intention réelle n'est pas claire. Il semble y avoir beaucoup de questions où les gens essaient d'expliciter des conversions entre des chaînes et des octets plutôt que de les laisser {In,Out}putStream{Read,Writ}ersfaire pour eux. Je me demande pourquoi?
tchrist le
1
@Michael: Merci, je suppose que cela a du sens. Mais cela rend aussi les choses plus difficiles que nécessaire, n'est-ce pas? Je n'aime pas beaucoup les langues qui fonctionnent de cette façon et j'essaie donc d'éviter de travailler avec elles. Je pense que le modèle Java de chaînes de caractères au lieu d'octets rend les choses beaucoup plus faciles. Perl et Python partagent également le modèle «tout est des chaînes Unicode». Oui, dans les trois, vous pouvez toujours obtenir des octets si vous y travaillez, mais en pratique, il semble rare que vous en ayez vraiment besoin: c'est un niveau assez bas. De plus, c'est un peu comme brosser un chat dans la mauvaise direction, si vous voyez ce que je veux dire. :)
tchrist

Réponses:

140

String les objets en Java utilisent le codage UTF-16 qui ne peut pas être modifié.

La seule chose qui peut avoir un encodage différent est un byte[]. Donc, si vous avez besoin de données UTF-8, vous avez besoin d'un fichier byte[]. Si vous avez un Stringqui contient des données inattendues, alors le problème est à un endroit antérieur qui a incorrectement converti certaines données binaires en a String(c'est-à-dire qu'il utilisait un mauvais encodage).

Joachim Sauer
la source
92
Techniquement parlant, byte [] n'a aucun encodage. L'encodage Byte array PLUS peut cependant vous donner une chaîne.
Peter Štibraný
1
@ Peter: vrai. Mais y attacher un encodage n'a de sens que pour byte[], cela n'a pas de sens pour String(à moins que l'encodage soit UTF-16, auquel cas cela a du sens mais il s'agit toujours d'informations inutiles).
Joachim Sauer
4
String objects in Java use the UTF-16 encoding that can't be modified. Avez-vous une source officielle pour cette citation?
Ahmad Hajjar
@AhmadHajjar docs.oracle.com/javase/10/docs/api/java/lang/… : "La plate-forme Java utilise la représentation UTF-16 dans les tableaux de caractères et dans les classes String et StringBuffer."
Maxi Gis
173

Que diriez-vous d'utiliser

ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(myString)
Amir Rachum
la source
Voir ma discussion avec Peter. Mais si son hypothèse sur la question est correcte, votre solution ne serait toujours pas une idée car elle renvoie un ByteBuffer.
Michael Borgwardt
8
Mais comment obtenir une chaîne encodée? il renvoie un ByteBuffer
Alex
7
@Alex: il n'est pas possible d'avoir une chaîne Java encodée en UTF-8. Vous voulez des octets, alors utilisez directement le ByteBuffer (peut même être la meilleure solution si votre objectif est de l'envoyer via une collection réseau) ou appelez array () dessus pour obtenir un octet []
Michael Borgwardt
2
Une autre chose qui peut être utile est d'utiliser l'énumération Charsets.UTF_8 de Guava au lieu d'une chaîne qui peut lever une exception UnsupportedEncodingException. String -> octets: myString.getBytes(Charsets.UTF_8)et octets -> Chaîne: new String(myByteArray, Charsets.UTF_8).
rire_man
24
Encore mieux, utilisez StandardCharsets.UTF_8. Disponible en Java 1.7+.
Kat
81

Dans Java7, vous pouvez utiliser:

import static java.nio.charset.StandardCharsets.*;

byte[] ptext = myString.getBytes(ISO_8859_1); 
String value = new String(ptext, UTF_8); 

Cela a l'avantage de getBytes(String)ne pas déclarer throws UnsupportedEncodingException.

Si vous utilisez une ancienne version de Java, vous pouvez déclarer vous-même les constantes du jeu de caractères:

import java.nio.charset.Charset;

public class StandardCharsets {
    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
    public static final Charset UTF_8 = Charset.forName("UTF-8");
    //....
}
rzymek
la source
2
C'est la bonne réponse. Si quelqu'un veut utiliser un type de données chaîne, il peut l'utiliser dans le bon format. Le reste des réponses pointe vers le type formaté en octets.
Neeraj Shukla
Fonctionne en 6. Merci.
Itsik Mauyhas
Bonne réponse pour moi aussi. Une chose cependant, quand j'ai utilisé comme ci-dessus, le caractère allemand a changé en?. Donc, j'ai utilisé ceci: byte [] ptext = myString.getBytes (UTF_8); Valeur de chaîne = nouvelle chaîne (ptext, UTF_8); Cela a bien fonctionné.
Farhan Hafeez
3
L'exemple de code n'a pas de sens. Si vous convertissez d'abord en ISO-8859-1, alors ce tableau d'octets n'est pas UTF-8, donc la ligne suivante est totalement incorrecte. Il travaillera pour les chaînes ASCII, bien sûr, mais alors vous pourriez aussi bien faire une simple copie: String value = new String(myString);.
Alexis Wilke
76

Utilisez à la byte[] ptext = String.getBytes("UTF-8");place de getBytes(). getBytes()utilise ce que l'on appelle le «codage par défaut», qui peut ne pas être UTF-8.

Peter Štibraný
la source
9
@Michael: il a clairement du mal à obtenir des octets à partir d'une chaîne. Comment getBytes (encodage) manque-t-il le point? Je pense que la deuxième ligne est là juste pour vérifier s'il peut la reconvertir.
Peter Štibraný
1
Je l'interprète comme ayant une chaîne cassée et j'essaye de la "réparer" en la convertissant en octets et inversement (malentendu courant). Il n'y a aucune indication réelle que la deuxième ligne vérifie simplement le résultat.
Michael Borgwardt
@Michael, non il n'y en a pas, c'est juste mon interprétation. Le vôtre est tout simplement différent.
Peter Štibraný
1
@Peter: vous avez raison, nous aurions besoin de clarifier Alex ce qu'il veut vraiment dire. Impossible d'annuler le vote défavorable à moins que la réponse ne soit modifiée ...
Michael Borgwardt
33

Une chaîne Java est toujours codée en interne en UTF-16 - mais vous devriez vraiment y penser comme ceci: un encodage est un moyen de traduire entre des chaînes et des octets.

Donc, si vous avez un problème d'encodage, au moment où vous avez String, il est trop tard pour le résoudre. Vous devez fixer l'endroit où vous créez cette chaîne à partir d'un fichier, d'une base de données ou d'une connexion réseau.

Michael Borgwardt
la source
1
C'est une erreur courante de croire que les chaînes sont codées en interne en UTF-16. Habituellement, ils le sont, mais si, ce n'est qu'un détail spécifique à l'implémentation de la classe String. Étant donné que le stockage interne des données de caractères n'est pas accessible via l'API publique, une implémentation String spécifique peut décider d'utiliser tout autre codage.
jarnbjo
4
@jarnbjo: L'API déclare explicitement "Une chaîne représente une chaîne au format UTF-16". Utiliser autre chose comme format interne serait très inefficace, et toutes les implémentations réelles que je connais utilisent UTF-16 en interne. Donc, à moins que vous ne puissiez en citer un qui ne le fait pas, vous vous engagez dans une coupe de cheveux assez absurde.
Michael Borgwardt
Est-il absurde de faire la distinction entre l'accès public et la représentation interne des structures de données?
jarnbjo
6
La JVM (dans la mesure où cela est pertinent pour la VM) utilise UTF-8 pour le codage de chaînes, par exemple dans les fichiers de classe. L'implémentation de java.lang.String est découplée de la JVM et je pourrais facilement implémenter la classe pour vous en utilisant n'importe quel autre encodage pour la représentation interne si cela est vraiment nécessaire pour que vous vous rendiez compte que votre réponse est incorrecte. Utiliser UTF-16 comme format interne est dans la plupart des cas également très inefficace en ce qui concerne la consommation de mémoire et je ne vois pas pourquoi, par exemple, les implémentations Java pour le matériel embarqué n'optimiseraient pas la mémoire au lieu des performances.
jarnbjo
1
@jarnbjo: Et une fois de plus: aussi longtemps que vous ne pouvez pas donner un exemple concret d'une machine virtuelle Java dont l' application API standard n'utiliser en interne autre chose que UTF-16 pour mettre en œuvre des chaînes, ma déclaration est correcte. Et non, la classe String n'est pas vraiment découplée de la JVM, à cause de choses comme intern () et le pool de constantes.
Michael Borgwardt
22

Vous pouvez essayer de cette façon.

byte ptext[] = myString.getBytes("ISO-8859-1"); 
String value = new String(ptext, "UTF-8"); 
user716840
la source
1
Je devenais fou. Merci d'obtenir les octets dans "ISO-8859-1" était d'abord la solution.
Gian Gomen
2
C'est faux. Si votre chaîne comprend des caractères Unicode, la convertir en 8859-1 va lever une exception ou pire vous donnera une chaîne non valide (peut-être la chaîne sans ces caractères avec le point de code 0x100 et plus).
Alexis Wilke
12

En un instant, j'ai traversé ce problème et j'ai réussi à le résoudre de la manière suivante

je dois d'abord importer

import java.nio.charset.Charset;

Ensuite, j'ai dû déclarer une constante à utiliser UTF-8etISO-8859-1

private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final Charset ISO = Charset.forName("ISO-8859-1");

Ensuite, je pourrais l'utiliser de la manière suivante:

String textwithaccent="Thís ís a text with accent";
String textwithletter="Ñandú";

text1 = new String(textwithaccent.getBytes(ISO), UTF_8);
text2 = new String(textwithletter.getBytes(ISO),UTF_8);
Quimbo
la source
1
solution parfaite.
Tunde Pizzle
9
String value = new String(myString.getBytes("UTF-8"));

et, si vous souhaitez lire un fichier texte avec "ISO-8859-1" codé:

String line;
String f = "C:\\MyPath\\MyFile.txt";
try {
    BufferedReader br = Files.newBufferedReader(Paths.get(f), Charset.forName("ISO-8859-1"));
    while ((line = br.readLine()) != null) {
        System.out.println(new String(line.getBytes("UTF-8")));
    }
} catch (IOException ex) {
    //...
}
fedesanp
la source
2

J'ai utilisé le code ci-dessous pour encoder le caractère spécial en spécifiant le format d'encodage.

String text = "This is an example é";
byte[] byteText = text.getBytes(Charset.forName("UTF-8"));
//To get original string from byte.
String originalString= new String(byteText , "UTF-8");
laxman954
la source
2

Un guide étape par étape rapide pour configurer l'encodage par défaut NetBeans UTF-8. En conséquence, NetBeans créera tous les nouveaux fichiers en encodage UTF-8.

Guide pas à pas de l'encodage par défaut NetBeans UTF-8

  • Accédez au dossier etc dans le répertoire d'installation de NetBeans

  • Modifier le fichier netbeans.conf

  • Rechercher la ligne netbeans_default_options

  • Ajoutez -J-Dfile.encoding = UTF-8 entre guillemets à l'intérieur de cette ligne

    (exemple: netbeans_default_options="-J-Dfile.encoding=UTF-8")

  • Redémarrez NetBeans

Vous définissez le codage par défaut de NetBeans UTF-8.

Vos netbeans_default_options peuvent contenir des paramètres supplémentaires entre guillemets. Dans ce cas, ajoutez -J-Dfile.encoding = UTF-8 à la fin de la chaîne. Séparez-le par un espace des autres paramètres.

Exemple:

netbeans_default_options = "- J-client -J-Xss128m -J-Xms256m -J-XX: PermSize = 32m -J-Dapple.laf.useScreenMenuBar = true -J-Dapple.awt.graphics.UseQuartz = true -J-Dsun. java2d.noddraw = true -J-Dsun.java2d.dpiaware = true -J-Dsun.zip.disableMemoryMapping = true -J-Dfile.encoding = UTF-8 "

voici le lien pour plus de détails

M. Laeeq Khan
la source
0

Cela a résolu mon problème

    String inputText = "some text with escaped chars"
    InputStream is = new ByteArrayInputStream(inputText.getBytes("UTF-8"));
Prasanth RJ
la source