So konvertieren Sie eine Zeichenfolge mit Unicode-Codierung in eine Zeichenfolge

84

Ich habe eine Zeichenfolge mit maskierten Unicode- Zeichen \uXXXXund möchte sie in reguläre Unicode-Buchstaben konvertieren. Zum Beispiel:

"\u0048\u0065\u006C\u006C\u006F World"

soll werden

"Hello World"

Ich weiß, dass beim Drucken der ersten Zeichenfolge diese bereits angezeigt wird Hello world. Mein Problem ist, dass ich Dateinamen aus einer Datei lese und dann nach ihnen suche. Die Dateinamen in der Datei werden mit Unicode-Codierung maskiert. Wenn ich nach den Dateien suche, kann ich sie nicht finden, da nach einer Datei mit \uXXXXihrem Namen gesucht wird .

SharonBL
quelle
Bist du sicher? Sie nehmen nicht an, dass die Zeichen einfach gedruckt werden, wenn Unicode entweicht?
Hot Licks
5
\u0048 ist H - sie sind ein und dasselbe. Zeichenfolgen in Java sind in Unicode.
Hot Licks
Ich denke, das Problem könnte sein, dass mein Java die API unix macht - die Zeichenfolge, die ich bekomme, ist ungefähr so ​​\ u3123 \ u3255_file_name.txt. Und Java verdeckt es nicht.
SharonBL
3
UTF-8 ist eine Unicode-Codierung.
Pavel Radzivilovsky
5
Dies ist keine Antwort auf Ihre Frage, aber lassen Sie mich den Unterschied zwischen Unicode und UTF-8 klären, den viele Leute durcheinander zu bringen scheinen. Unicode ist ein besonderes eins-zu-eins - Mapping zwischen den Zeichen , wie wir sie kennen ( a, b, $, £usw.) zu den ganzen Zahlen. Das Symbol hat Abeispielsweise die Nummer 65 und \nist 10. Dies hat nichts damit zu tun, wie Zeichenfolgen oder Zeichen auf der Festplatte oder in einer Textdatei dargestellt werden. UTF-8 ist eine Spezifikation (dh Codierung), wie diese Ganzzahlen (dh Symbole) als Bytes (Bitfolgen) dargestellt werden, damit sie eindeutig aus einer Datei geschrieben und gelesen werden können.
DustByte

Antworten:

49

Technisch gesehen:

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

konvertiert es automatisch in "Hello World", also gehe ich davon aus, dass Sie die Zeichenfolge aus einer Datei einlesen. Um es in "Hallo" umzuwandeln, müssen Sie den Text in die separaten Unicode-Ziffern analysieren (nehmen Sie die \uXXXXund erhalten Sie einfach XXXX) Integer.ParseInt(XXXX, 16), um einen Hex-Wert zu erhalten, und dann den Fall, charum das tatsächliche Zeichen zu erhalten.

Bearbeiten: Code, um dies zu erreichen:

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
NominSim
quelle
Scheint, das könnte die Lösung sein. Haben Sie eine Idee, wie ich es in Java machen kann - kann ich es mit String.replaceAll oder so machen?
SharonBL
@ SharonBL Ich habe mit etwas Code aktualisiert, sollte dir zumindest eine Vorstellung davon geben, wo ich anfangen soll.
NominSim
2
Vielen Dank für Ihre Hilfe! Ich habe auch eine andere Lösung dafür gefunden: String s = StringEscapeUtils.unescapeJava ("\\ u20ac \\ n"); es macht die Arbeit!
SharonBL
2
Versuchen Sie, die von der Standard Java Library bereitgestellten Methoden neu zu erfinden. Überprüfen Sie einfach die reine Implementierung stackoverflow.com/a/39265921/1511077
Evgeny Lebedev
1
Ich bin immer wieder erstaunt, wenn eine Antwort " Das Rad neu erfinden " so viele Stimmen erhält.
Pedro Lobito
93

Das Apache Commons Lang StringEscapeUtils.unescapeJava () kann es ordnungsgemäß dekodieren.

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
Tony
quelle
String sJava = "\ u0048 \ u0065 \ u006C \ u006C \ u006F"; -----> Bitte ändern Sie einfach.
Shreyansh Shah
30

Sie können StringEscapeUtilsvon Apache Commons Lang verwenden , dh:

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

Pedro Lobito
quelle
5
Nach dem Hinzufügen der Abhängigkeit in build.gradle: Kompilieren Sie 'commons-lang: commons-lang: 2.6' über dem Funktionieren.
Joseph Mekwan
8

Diese einfache Methode funktioniert in den meisten Fällen, stolpert jedoch über "u005Cu005C", das in die Zeichenfolge "\ u0048" dekodiert werden soll, aber tatsächlich "H" dekodiert, wenn der erste Durchgang "\ u0048" als Arbeitszeichenfolge erzeugt wird dann von der while-Schleife erneut verarbeitet.

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;
}
Andrew Pate
quelle
Versuchen Sie, die von der Standard Java Library bereitgestellten Methoden neu zu erfinden. Überprüfen Sie einfach die reine Implementierung stackoverflow.com/a/39265921/1511077
Evgeny Lebedev
1
Danke @EvgenyLebedev ... die Standardbibliothek sieht gut aus und wurde vermutlich gründlich getestet, sehr geschätzt.
Andrew Pate
7

Kürzere Version:

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;
}
ssuukk
quelle
Versuchen Sie, die von der Standard Java Library bereitgestellten Methoden neu zu erfinden. Überprüfen Sie einfach die reine Implementierung stackoverflow.com/a/39265921/1511077
Evgeny Lebedev
5

StringEscapeUtils aus der Bibliothek org.apache.commons.lang3 ist ab 3.6 veraltet .

Sie können also stattdessen die neue Commons-Text- Bibliothek verwenden:

compile 'org.apache.commons:commons-text:1.9'

OR

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-text</artifactId>
   <version>1.9</version>
</dependency>

Beispielcode:

org.apache.commons.text.StringEscapeUtils.unescapeJava(escapedString);
Bogdan Kobylynskyi
quelle
4

Aus Ihrer Frage geht nicht ganz klar hervor, aber ich gehe davon aus, dass Sie sagen, dass Sie eine Datei haben, in der jede Zeile dieser Datei ein Dateiname ist. Und jeder Dateiname ist ungefähr so:

\u0048\u0065\u006C\u006C\u006F

Mit anderen Worten, sind die Zeichen in der Datei von Dateinamen \, u, 0, 0, 4, 8und so weiter.

Wenn ja, wird erwartet, was Sie sehen. Java übersetzt nur \uXXXXSequenzen in String-Literalen im Quellcode (und beim Einlesen gespeicherter PropertiesObjekte). Wenn Sie die Inhalte lesen Datei , die Sie Sie eine Zeichenfolge der Zeichen bestehend haben \, u, 0, 0, 4, 8und so weiter und nicht die Zeichenfolge Hello.

So müssen Sie diese Zeichenfolge analysieren die extrahieren 0048, 0065, Stücke usw. und sie dann konvertieren chars und einen String aus diesen machen chars und dann die Zeichenfolge an die Routine übergeben , die die Datei öffnet.

QuantumMechanic
quelle
3

Ich wollte nur meine Version mit Regex beisteuern:

private static final String UNICODE_REGEX = "\\\\u([0-9a-f]{4})";
private static final Pattern UNICODE_PATTERN = Pattern.compile(UNICODE_REGEX);
...
String message = "\u0048\u0065\u006C\u006C\u006F World";
Matcher matcher = UNICODE_PATTERN.matcher(message);
StringBuffer decodedMessage = new StringBuffer();
while (matcher.find()) {
  matcher.appendReplacement(
      decodedMessage, String.valueOf((char) Integer.parseInt(matcher.group(1), 16)));
}
matcher.appendTail(decodedMessage);
System.out.println(decodedMessage.toString());
robertokl
quelle
2

Ich habe eine leistungsfähige und fehlerfreie Lösung geschrieben:

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();
}
neoedmund
quelle
1

Versuchen

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

Ein einfacher Weg, den ich mit JsonObject kenne:

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

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

Hier ist meine Lösung ...

                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;
                    }
                };
AndyW58
quelle
Versuchen Sie, die von der Standard Java Library bereitgestellten Standardmethoden neu zu erfinden. Überprüfen Sie einfach die reine Implementierung stackoverflow.com/a/39265921/1511077
Evgeny Lebedev
1

Schnell

 fun unicodeDecode(unicode: String): String {
        val stringBuffer = StringBuilder()
        var i = 0
        while (i < unicode.length) {
            if (i + 1 < unicode.length)
                if (unicode[i].toString() + unicode[i + 1].toString() == "\\u") {
                    val symbol = unicode.substring(i + 2, i + 6)
                    val c = Integer.parseInt(symbol, 16)
                    stringBuffer.append(c.toChar())
                    i += 5
                } else stringBuffer.append(unicode[i])
            i++
        }
        return stringBuffer.toString()
    }
Wefyns
quelle
0

Eigentlich habe ich eine Open Source-Bibliothek geschrieben, die einige Dienstprogramme enthält. Eine davon ist die Konvertierung einer Unicode-Sequenz in String und umgekehrt. Ich fand es sehr nützlich. Hier ist das Zitat aus dem Artikel über diese Bibliothek über Unicode-Konverter:

Die Klasse StringUnicodeEncoderDecoder verfügt über Methoden, mit denen ein String (in einer beliebigen Sprache) in eine Folge von Unicode-Zeichen konvertiert werden kann und umgekehrt. Zum Beispiel wird ein String "Hello World" in konvertiert

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

und kann wieder hergestellt werden.

Hier ist der Link zum gesamten Artikel, der erklärt, welche Dienstprogramme die Bibliothek hat und wie die Bibliothek sie verwenden kann. Es ist als Maven-Artefakt oder als Quelle von Github erhältlich. Es ist sehr einfach zu bedienen. Open Source Java-Bibliothek mit Stack-Trace-Filterung, Silent String-Parsing-Unicode-Konverter und Versionsvergleich

Michael Gantman
quelle
0

Für Java 9+ können Sie die neue replaceAll- Methode der Matcher- Klasse verwenden.

private static final Pattern UNICODE_PATTERN = Pattern.compile("\\\\u([0-9A-Fa-f]{4})");

public static String unescapeUnicode(String unescaped) {
    return UNICODE_PATTERN.matcher(unescaped).replaceAll(r -> String.valueOf((char) Integer.parseInt(r.group(1), 16)));
}

public static void main(String[] args) {
    String originalMessage = "\\u0048\\u0065\\u006C\\u006C\\u006F World";
    String unescapedMessage = unescapeUnicode(originalMessage);
    System.out.println(unescapedMessage);
}

Ich glaube, der Hauptvorteil dieses Ansatzes gegenüber unescapeJava von StringEscapeUtils (abgesehen davon, dass keine zusätzliche Bibliothek verwendet wird) besteht darin, dass Sie nur die Unicode-Zeichen konvertieren können (wenn Sie dies wünschen), da letztere alle maskierten Java-Zeichen (wie \ n oder \ t) konvertieren ). Wenn Sie lieber alle maskierten Zeichen konvertieren möchten, ist die Bibliothek die beste Option.

Marcelo Barros
quelle
0

@NominSim Möglicherweise gibt es ein anderes Zeichen, daher sollte ich es anhand der Länge erkennen.

private String forceUtf8Coding(String str) {
    str = str.replace("\\","");
    String[] arr = str.split("u");
    StringBuilder text = new StringBuilder();
    for(int i = 1; i < arr.length; i++){
        String a = arr[i];
        String b = "";
        if (arr[i].length() > 4){
            a = arr[i].substring(0, 4);
            b = arr[i].substring(4);
        }
        int hexVal = Integer.parseInt(a, 16);
        text.append((char) hexVal).append(b);
    }
    return text.toString();
}
Jun.wan
quelle
0

UnicodeUnescapervon org.apache.commons:commons-textist auch akzeptabel.

new UnicodeUnescaper().translate("\u0048\u0065\u006C\u006C\u006F World") kehrt zurück "Hello World"

anton
quelle
-1

Eine alternative Möglichkeit, dies zu erreichen, könnte die Verwendung von chars()Java 9 sein. Dies kann verwendet werden, um die Zeichen zu durchlaufen und sicherzustellen, dass alle Zeichen, die einem Ersatzcodepunkt zugeordnet sind, nicht interpretiert durchlaufen werden. Dies kann verwendet werden als: -

String myString = "\u0048\u0065\u006C\u006C\u006F World";
myString.chars().forEach(a -> System.out.print((char)a));
// would print "Hello World"
Naman
quelle
-1

Ich stellte fest, dass sich viele der Antworten nicht mit dem Thema "Ergänzende Zeichen" befassten. Hier ist der richtige Weg, um es zu unterstützen. Keine Bibliotheken von Drittanbietern, reine Java-Implementierung.

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
lovestackh343
quelle
Funktioniert nicht, wenn die Zeichenfolge keine Unicode-Zeichen enthält, z. B.: Href = \ u0022 \ / de \ / blog \ / d-Tag-Schutz-Europa-seine-Dämonen \ u0022 \ u003E \ n
Mohsen Abasi
-1

Lösung für Kotlin:

val sourceContent = File("test.txt").readText(Charset.forName("windows-1251"))
val result = String(sourceContent.toByteArray())

Kotlin verwendet UTF-8 überall als Standardcodierung.

Methode toByteArray()hat Standardargument - Charsets.UTF_8.

Evgeny Lebedev
quelle
Es ist keine Antwort ohne echte Beispiele für Inhalte, die nicht mit Suggestor bytearray-way "konvertiert" werden können. können Sie es zur Verfügung stellen?
Evgeny Lebedev
String(string.toByteArray())erreicht buchstäblich nichts.
Rustyx
@rustyx Methode toByteArray()hat Standardargument mit Charsets.UTF_8. Anschließend erstellen Sie eine Zeichenfolge aus Bytearray mit der erforderlichen Codierung. Ich habe heute mit windows-1251utf-8 getestet , es funktioniert. Außerdem habe ich einen Vergleich auf Byte-Ebene durchgeführt :)
Evgeny Lebedev
@rustyx hier ist ein Kern für Sie - gist.github.com/lebe-dev/31e31a3399c7885e298ed86810504676
Evgeny Lebedev