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 .


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

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

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");


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;
}

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;
}

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);

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.



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());

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

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))}

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

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;
                    }
                };

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()
    }

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


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.


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

0

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

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


-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"

-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

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.


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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.