web-dev-qa-db-fra.com

Comment convertir une chaîne encodée en Unicode en chaîne de lettres

J'ai une chaîne avec Unicode encoding, \uXXXX et je veux la convertir en lettre normale ( UTF-8 ). Par exemple:

String myString = "\u0048\u0065\u006C\u006C\u006F World";

devraient devenir

"Hello World"

Je sais que lorsque j'imprime la chaîne, il affiche Hello world. Mon problème est que je lis les noms de fichiers d'un fichier sur une machine Unix, puis je les recherche. Les noms de fichiers sont codés en Unicode et lorsque je recherche les fichiers, je ne les trouve pas, car ils recherchent un fichier avec \uXXXX dans son nom.

55
SharonBL

Faire techniquement:

String myString = "\u0048\u0065\u006C\u006C\u006F World";

le convertit automatiquement en "Hello World", donc je suppose que vous lisez dans la chaîne à partir d'un fichier. Pour le convertir en "Bonjour", vous devrez analyser le texte dans les chiffres unicodes séparés (prenez le \uXXXX et récupérez simplement XXXX), puis exécutez Integer.ParseInt(XXXX, 16) pour obtenir une valeur hexadécimale, puis définissez la valeur char personnage.

Edit: Du code pour accomplir ceci:

String str = myString.split(" ")[0];
str = str.replace("\\","");
String[] arr = str.split("u");
String text = "";
for(int i = 1; i < arr.length; i++){
    int hexVal = Integer.parseInt(arr[i], 16);
    text += (char)hexVal;
}
// Text will now have Hello
37
NominSim

Le Apache Commons LangStringEscapeUtils.unescapeJava () peut le décoder correctement. 

import org.Apache.commons.lang.StringEscapeUtils;

@Test
public void testUnescapeJava() {
    String sJava="\\u0048\\u0065\\u006C\\u006C\\u006F";
    System.out.println("StringEscapeUtils.unescapeJava(sJava):\n" + StringEscapeUtils.unescapeJava(sJava));
}


 output:
 StringEscapeUtils.unescapeJava(sJava):
 Hello
71
Tony

Vous pouvez utiliser StringEscapeUtils de Apache Commons Lang , c'est-à-dire:

String Title = StringEscapeUtils.unescapeJava("\u0048\u0065\u006C\u006C\u006F");

22
Pedro Lobito

Codages et chaînes d'octets

En Java, la conversion du flux d'octets (byte []) dans la chaîne (String) et son retour à la classe String présentent les caractéristiques suivantes:

Le constructeur String (byte [] bytes, String enc) reçoit le flux d'octets en entrée avec leur codage; si l'encodage est omis, il sera accepté par défaut

getBytes Method (String enc) renvoie un flux d'octets enregistré dans le codage spécifié; l'encodage peut également être omis. 

try {
    String myString = "\u0048\u0065\u006C\u006C\u006F World";
    byte[] utf8Bytes = myString.getBytes("UTF8");
    String text = new String(utf8Bytes,"UTF8");
}
catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}

METTRE À JOUR:

Depuis Java 1.7, utilisez StandardCharsets.UTF_8:

String utf8Text = "\u0048\u0065\u006C\u006C\u006F World";
byte[] bytes = utf8Text.getBytes(StandardCharsets.UTF_8);
String text = new String(bytes, StandardCharsets.UTF_8);
15
bigspawn

Cette méthode simple fonctionnera dans la plupart des cas, mais trébucherait sur quelque chose comme "u005Cu005C" qui devrait être décodé en chaîne "\ u0048" mais décoderait en fait "H" car le premier passage produirait "\ u0048" est ensuite traité à nouveau par la boucle while.

static final String decode(final String in)
{
    String working = in;
    int index;
    index = working.indexOf("\\u");
    while(index > -1)
    {
        int length = working.length();
        if(index > (length-6))break;
        int numStart = index + 2;
        int numFinish = numStart + 4;
        String substring = working.substring(numStart, numFinish);
        int number = Integer.parseInt(substring,16);
        String stringStart = working.substring(0, index);
        String stringEnd   = working.substring(numFinish);
        working = stringStart + ((char)number) + stringEnd;
        index = working.indexOf("\\u");
    }
    return working;
}
7
andrew pate

Cela ne ressort pas clairement de votre question, mais je suppose que vous dites que vous avez un fichier où chaque ligne de ce fichier est un nom de fichier. Et chaque nom de fichier ressemble à ceci:

\u0048\u0065\u006C\u006C\u006F

En d'autres termes, les caractères dans le fichier des noms de fichiers sont \, u, 0, 0, 4, 8 et ainsi de suite.

Si c'est le cas, ce que vous voyez est attendu. Java ne traduit que les séquences \uXXXX en chaînes littérales en code source (et lors de la lecture d'objets Properties stockés). Lorsque vous lisez le contenu de votre fichier, vous obtenez une chaîne composée des caractères \, u, 0, 0, 4, 8 et ainsi de suite et not de la chaîne Hello.

Vous devrez donc analyser cette chaîne pour extraire les éléments 0048, 0065, etc., puis les convertir en chars, créer une chaîne à partir de ces chars, puis les transmettre à la routine qui ouvre le fichier.

4
QuantumMechanic

Version plus courte:

public static String unescapeJava(String escaped) {
    if(escaped.indexOf("\\u")==-1)
        return escaped;

    String processed="";

    int position=escaped.indexOf("\\u");
    while(position!=-1) {
        if(position!=0)
            processed+=escaped.substring(0,position);
        String token=escaped.substring(position+2,position+6);
        escaped=escaped.substring(position+6);
        processed+=(char)Integer.parseInt(token,16);
        position=escaped.indexOf("\\u");
    }
    processed+=escaped;

    return processed;
}
3
ssuukk

essayer

private static final Charset UTF_8 = Charset.forName("UTF-8");
private String forceUtf8Coding(String input) {return new String(input.getBytes(UTF_8), UTF_8))}
3
haohcraft

un moyen facile, je sais en utilisant JsonObject:

try {
    JSONObject json = new JSONObject();
    json.put("string", myString);
    String converted = json.getString("string");

} catch (JSONException e) {
    e.printStackTrace();
}
1
Ashkan Ghodrat

J'ai écrit une solution performancée et résistante aux erreurs:

public static final String decode(final String in) {
    int p1 = in.indexOf("\\u");
    if (p1 < 0)
        return in;
    StringBuilder sb = new StringBuilder();
    while (true) {
        int p2 = p1 + 6;
        if (p2 > in.length()) {
            sb.append(in.subSequence(p1, in.length()));
            break;
        }
        try {
            int c = Integer.parseInt(in.substring(p1 + 2, p1 + 6), 16);
            sb.append((char) c);
            p1 += 6;
        } catch (Exception e) {
            sb.append(in.subSequence(p1, p1 + 2));
            p1 += 2;
        }
        int p0 = in.indexOf("\\u", p1);
        if (p0 < 0) {
            sb.append(in.subSequence(p1, in.length()));
            break;
        } else {
            sb.append(in.subSequence(p1, p0));
            p1 = p0;
        }
    }
    return sb.toString();
}
0
neoedmund

StringEscapeUtils de la bibliothèque org.Apache.commons.lang3 est obsolète à partir de 3.6.

Vous pouvez donc utiliser leur nouvelle bibliothèque commons-text :

compile 'org.Apache.commons:commons-text:1.7'

OR

<dependency>
   <groupId>org.Apache.commons</groupId>
   <artifactId>commons-text</artifactId>
   <version>1.7</version>
</dependency>

Exemple de code:

org.Apache.commons.text.StringEscapeUtils.unescapeJava(escapedString);
0
Bogdan Kobylynskyi

Voici ma solution ...

                String decodedName = JwtJson.substring(startOfName, endOfName);

                StringBuilder builtName = new StringBuilder();

                int i = 0;

                while ( i < decodedName.length() )
                {
                    if ( decodedName.substring(i).startsWith("\\u"))
                    {
                        i=i+2;
                        builtName.append(Character.toChars(Integer.parseInt(decodedName.substring(i,i+4), 16)));
                        i=i+4;
                    }
                    else
                    {
                        builtName.append(decodedName.charAt(i));
                        i = i+1;
                    }
                };
0
AndyW58

Mises à jour concernant les réponses suggérant d’utiliser The Apache Commons Lang's, StringEscapeUtils.unescapeJava () il est devenu obsolète, le remplacement est Apache Commons Text ' StringEscapeUtils.unescapeJava ()

0
user7294900

Deux autres façons de faire serait

//This is what StringBuilder internally does on calling toString() Method
char[] charArray = "\u0048\u0065\u006C\u006C\u006F World".toCharArray();
String output = new String(charArray, 0, charArray.length);
//To do it in single line 
String output = new StringBuilder("\u0048\u0065\u006C\u006C\u006F World").toString();
0
Manoj Krishna

J'ai trouvé que beaucoup de réponses n'abordaient pas la question des "caractères supplémentaires". Voici la bonne façon de le supporter. Pas de bibliothèques tierces, implémentation Java pure.

http://www.Oracle.com/us/technologies/Java/supplementary-142654.html

public static String fromUnicode(String unicode) {
    String str = unicode.replace("\\", "");
    String[] arr = str.split("u");
    StringBuffer text = new StringBuffer();
    for (int i = 1; i < arr.length; i++) {
        int hexVal = Integer.parseInt(arr[i], 16);
        text.append(Character.toChars(hexVal));
    }
    return text.toString();
}

public static String toUnicode(String text) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < text.length(); i++) {
        int codePoint = text.codePointAt(i);
        // Skip over the second char in a surrogate pair
        if (codePoint > 0xffff) {
            i++;
        }
        String hex = Integer.toHexString(codePoint);
        sb.append("\\u");
        for (int j = 0; j < 4 - hex.length(); j++) {
            sb.append("0");
        }
        sb.append(hex);
    }
    return sb.toString();
}

@Test
public void toUnicode() {
    System.out.println(toUnicode("????"));
    System.out.println(toUnicode("????"));
    System.out.println(toUnicode("Hello World"));
}
// output:
// \u1f60a
// \u1f970
// \u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064

@Test
public void fromUnicode() {
    System.out.println(fromUnicode("\\u1f60a"));
    System.out.println(fromUnicode("\\u1f970"));
    System.out.println(fromUnicode("\\u0048\\u0065\\u006c\\u006c\\u006f\\u0020\\u0057\\u006f\\u0072\\u006c\\u0064"));
}
// output:
// ????
// ????
// Hello World
0
lovestackh343

Solution pour Kotlin:

val result = String(someText.toByteArray())

Kotlin utilise UTF-8 partout comme encodage par défaut

Vous pouvez aussi l'implémenter comme extension pour la classe String:

fun String.unescape(): String {
    return String(this.toByteArray())
}

et ensuite utilisez-le simple:

val result = someText.unescape()

;)

0
Evgeny Lebedev

En fait, j'ai écrit une bibliothèque Open Source contenant des utilitaires. L'un d'eux consiste à convertir une séquence Unicode en String et inversement. Je l'ai trouvé très utile. Voici la citation de l'article sur cette bibliothèque sur le convertisseur Unicode:

La classe StringUnicodeEncoderDecoder a des méthodes permettant de convertir un Chaîne (dans n'importe quelle langue) en une séquence de caractères Unicode et vice versa. Par exemple, une chaîne "Hello World" sera convertie en

"\ u0048\u0065\u006c\u006c\u006f\u0020\u0057\u006f\u0072\u006c\u0064"

et peut être restauré.

Voici le lien vers l'article complet qui explique quels utilitaires ont la bibliothèque et comment obtenir son utilisation par la bibliothèque. Il est disponible sous forme d'artefact Maven ou de source auprès de Github. C'est très facile à utiliser. Bibliothèque Java Open Source avec filtrage de trace de pile, conversion silencieuse de chaînes Unicode et comparaison de versions

0
Michael Gantman