webentwicklung-frage-antwort-db.com.de

Wie konvertiert man\uXXXX Unicode in UTF-8 mit Konsolentools in * nix?

Ich verwende curl, um eine URL-Antwort zu erhalten. Es handelt sich um eine JSON-Antwort, die aus Unicode-Zeichen bestehende nationale Zeichen wie\u0144 (ń)und\u00f3 (ó)enthält. 

Wie kann ich sie in UTF-8 oder eine andere Kodierung konvertieren, um sie in einer Datei zu speichern?

39
Krzysztof Wolny

Ich weiß nicht, welche Distribution Sie verwenden, aber uni2ascii sollte enthalten sein.

$ Sudo apt-get install uni2ascii

Es hängt nur von libc6 ab, daher ist es eine leichte Lösung (uni2ascii i386 4.18-2 ist auf Ubuntu 55,0 kB)!

Dann verwenden Sie es:

$ echo 'Character 1: \u0144, Character 2: \u00f3' | ascii2uni -a U -q
Character 1: ń, Character 2: ó
29
raphaelh

Vielleicht etwas hässlich, aber echo -e sollte es tun:

echo -en "$(curl $URL)"

-e interpretiert Escapezeichen, -n unterdrückt die Newline, die echo normalerweise hinzufügen würde.

Hinweis: Der \u-Escape funktioniert im bash-eingebauten echo, jedoch nicht im /usr/bin/echo.

Wie in den Kommentaren darauf hingewiesen, handelt es sich um bash 4.2+, und 4.2.x hat einen Fehler, der 0x00ff/17-Werte (0x80-0xff) verarbeitet.

37
Kevin

Ich fand native2ascii von JDK als die beste Möglichkeit, dies zu tun:

native2ascii -encoding UTF-8 -reverse src.txt dest.txt

Eine ausführliche Beschreibung finden Sie hier: http://docs.Oracle.com/javase/1.5.0/docs/tooldocs/windows/native2ascii.html

Update: Nicht mehr verfügbar seit JDK9: https://bugs.openjdk.Java.net/browse/JDK-8074431

29
Krzysztof Wolny

Angenommen, der \u folgt immer genau 4 Hex-Ziffern:

#!/usr/bin/Perl

use strict;
use warnings;

binmode(STDOUT, ':utf8');

while (<>) {
    s/\\u([0-9a-fA-F]{4})/chr(hex($1))/eg;
    print;
}

Die Variable binmode versetzt die Standardausgabe in den UTF-8-Modus. Der Befehl s... ersetzt jedes Vorkommen von \u, gefolgt von 4 Hexadezimalstellen mit dem entsprechenden Zeichen. Das Suffix e bewirkt, dass die Ersetzung als Ausdruck ausgewertet wird und nicht als Zeichenfolge behandelt wird. Die Variable g sagt, dass alle Vorkommen ersetzt werden sollen und nicht nur das erste.

Sie können das Obige in einer Datei in Ihrem $PATH speichern (vergessen Sie nicht den chmod +x). Es filtert die Standardeingabe (oder eine oder mehrere in der Befehlszeile angegebene Dateien) zur Standardausgabe.

20
Keith Thompson

verwenden Sie /usr/bin/printf "\u0160ini\u010di Ho\u0161i - A\u017e sa skon\u010d\u00ed zima", um eine korrekte Konvertierung von Unicode in Utf8 zu erhalten.

9
andrej

Verlassen Sie sich nicht auf Regex: JSON hat einige seltsame Eckfälle mit \u-Escape-Zeichen und Nicht-BMP-Codepunkten. (Insbesondere codiert JSON einen Codepunkt mit two \u - Escape.) Wenn Sie davon ausgehen, dass eine Escape-Sequenz in einen Codepunkt übersetzt wird, sind Sie für diesen Text verdammt.

Die Verwendung eines vollständigen JSON-Parsers aus der Sprache Ihrer Wahl ist wesentlich robuster:

$ echo '["foo bar \u0144\n"]' | python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin)[0].encode("utf-8"))'

Das füttert die Daten einfach in dieses kurze Python-Skript:

import json
import sys

data = json.load(sys.stdin)
data = data[0] # change this to find your string in the JSON
sys.stdout.write(data.encode('utf-8'))

Von denen Sie als foo.py speichern und als curl ... | foo.py aufrufen können

Ein Beispiel, bei dem die meisten anderen Versuche in dieser Frage gebrochen werden, ist "\ud83d\udca3":

% printf '"\\ud83d\\udca3"' | python2 -c 'import json, sys; sys.stdout.write(json.load(sys.stdin)[0].encode("utf-8"))'; echo
????
# echo will result in corrupt output:
% echo -e $(printf '"\\ud83d\\udca3"') 
"������"
# native2ascii won't even try (this is correct for its intended use case, however, just not ours):
% printf '"\\ud83d\\udca3"' | native2ascii -encoding utf-8 -reverse
"\ud83d\udca3"
9
Thanatos

Vorwort: Keine der vorgestellten Antworten auf diese Frage löste ein langjähriges Problem in Telegramm-Bot-Bash. Nur die python -Lösung von Thanatos hat funktioniert!

Dies liegt daran, dass JSON einen Codepunkt mit zwei Escape-Zeichen codiert .


Hier finden Sie zwei Ersetzungen für echo -e und printf '%s'

REINE bash Variante als Funktion. Fügen Sie oben in Ihr Skript ein und dekodieren Sie damit Ihre JSON-Zeichenfolgen in bash:

#!/bin/bash
#
# pure bash implementaion, done by KayM (@gnadelwartz)
# see https://stackoverflow.com/a/55666449/9381171
  JsonDecode() {
     local out="$1"
     local remain=""   
     local regexp='(.*)\\u[dD]([0-9a-fA-F]{3})\\u[dD]([0-9a-fA-F]{3})(.*)'
     while [[ "${out}" =~ $regexp ]] ; do
           # match 2 \udxxx hex values, calculate new U, then split and replace
           local W1="$(( ( 0xd${BASH_REMATCH[2]} & 0x3ff) <<10 ))"
           local W2="$(( 0xd${BASH_REMATCH[3]} & 0x3ff ))"
           U="$(( ( W1 | W2 ) + 0x10000 ))"
           remain="$(printf '\\U%8.8x' "${U}")${BASH_REMATCH[4]}${remain}"
           out="${BASH_REMATCH[1]}"
     done
     echo -e "${out}${remain}"
  }

# Some tests ===============
$ JsonDecode 'xxx \ud83d\udc25 xxxx' -> xxx ???? xxxx
$ JsonDecode '\ud83d\udc25' -> ????
$ JsonDecode '\u00e4 \u00e0 \u00f6 \u00f4 \u00fc \u00fb \ud83d\ude03 \ud83d\ude1a \ud83d\ude01 \ud83d\ude02 \ud83d\udc7c \ud83d\ude49 \ud83d\udc4e \ud83d\ude45 \ud83d\udc5d \ud83d\udc28 \ud83d\udc25 \ud83d\udc33 \ud83c\udf0f \ud83c\udf89 \ud83d\udcfb \ud83d\udd0a \ud83d\udcec \u2615 \ud83c\udf51'
ä à ö ô ü û ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? ☕ ????

# decode 100x string with 25 JSON UTF-16 vaules
$ time for x in $(seq 1 100); do JsonDecode '\u00e4 \u00e0 \u00f6 \u00f4 \u00fc \u00fb \ud83d\ude03 \ud83d\ude1a \ud83d\ude01 \ud83d\ude02 \ud83d\udc7c \ud83d\ude49 \ud83d\udc4e \ud83d\ude45 \ud83d\udc5d \ud83d\udc28 \ud83d\udc25 \ud83d\udc33 \ud83c\udf0f \ud83c\udf89 \ud83d\udcfb \ud83d\udd0a \ud83d\udcec \u2615 \ud83c\udf51' >/dev/null ; done

real    0m2,195s
user    0m1,635s
sys     0m0,647s

GEMISCHTE Lösung mit Phyton-Variante von Thanatos:

# usage: JsonDecode "your bash string containing \uXXXX extracted from JSON"
 JsonDecode() {
     # wrap string in "", replace " by \"
     printf '"%s\\n"' "${1//\"/\\\"}" |\
     python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin).encode("utf-8"))'
 }

-


Der Testfall für diejenigen, die sich für die anderen beworbenen Lösungen einsetzen, funktioniert:

# test='???? ???? ❤️ ???? ????' from JSON
$ export test='\uD83D\uDE01 \uD83D\uDE18 \u2764\uFE0F \uD83D\uDE0A \uD83D\uDC4D'

$ printf '"%s\\n"' "${test}" | python -c 'import json, sys; sys.stdout.write(json.load(sys.stdin).encode("utf-8"))' >phyton.txt
$ echo -e "$test" >echo.txt

$ cat -v phyton.txt
M-pM-^_M-^XM-^A M-pM-^_M-^XM-^X M-bM-^]M-$M-oM-8M-^O M-pM-^_M-^XM-^J M-pM-^_M-^QM-^M

$ cat -v echo.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M

Wie Sie leicht sehen können, ist die Ausgabe unterschiedlich. Die anderen hochgestuften Lösungen bieten dieselbe falsche Ausgabe für JSON-Zeichenfolgen wie echo -e:

$ ascii2uni -a U -q >uni2ascii.txt <<EOF
$test
EOF

$ cat -v uni2ascii.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M

$ printf "$test\n" >printf.txt
$ cat -v printf.txt
M-mM- M-=M-mM-8M-^A M-mM- M-=M-mM-8M-^X M-bM-^]M-$M-oM-8M-^O M-mM- M-=M-mM-8M-^J M-mM- M-=M-mM-1M-^M

$ echo "$test" | iconv -f Unicode >iconf.txt                                                                                     

$ cat -v iconf.txt
M-gM-^UM-^\M-cM-!M-^DM-dM-^PM-3M-gM-^UM-^\M-dM-^UM-^DM-cM-^DM-0M-eM-0M- M-dM-^QM-5M-cM-^LM-8M-eM-1M-^DM-dM-^QM-5M-cM-^EM-^EM-bM-^@M-8M-gM-^UM-^\M-cM-^\M-2M-cM-^PM-6M-gM-^UM-^\M-dM-^UM-^FM-dM-^XM-0M-eM-0M- M-dM-^QM-5M-cM-^LM-8M-eM-1M-^DM-dM-^QM-5M-cM-^AM-^EM-bM-^AM-^AM-gM-^UM-^\M-cM-!M-^DM-dM-^PM-3M-gM-^UM-^\M-dM-^MM-^DM-dM-^PM-4r
1
Kay Marquardt

jetzt habe ich die beste antwort! Verwenden Sie jq

Windows:

type in.json | jq > out.json

Lunix:

cat in.json | jq > out.json

Mit Perl/Python ist es sicherlich schneller als jede Antwort. Ohne Parameter formatiert es den Json und konvertiert\uXXXX in utf8. Es kann auch für Json-Abfragen verwendet werden. Sehr schönes Werkzeug!

1
Smit Johnth
iconv -f Unicode fullOrders.csv > fullOrders-utf8.csv
0
Tanguy

Verwenden Sie den von POSIX vorgeschriebenen b-Konvertierungsspezifizierer:

Ein zusätzliches Konvertierungs-Spezifikationszeichen, b, wird wie folgt unterstützt. Das Argument soll eine Zeichenfolge sein, die Backslash-Escape-Sequenzen enthalten kann.
- http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

expand_escape_sequences() {
  printf %b "$1"
}

Prüfung:

s='\u0160ini\u010di Ho\u0161i - A\u017e sa skon\u010d\u00ed zima A percent sign % OK?'
expand_escape_sequences "$s"

# output: Šiniči Hoši - Až sa skončí zima A percent sign % OK?

HINWEIS: Wenn Sie den %b-Formatbezeichner entfernen, führt das Prozentzeichen zu einem Fehler wie:

-bash: printf: `O': invalid format character

Erfolgreich getestet mit beiden bash-basierten Variablen printf und /usr/bin/printf in meiner Linux-Distribution (Fedora 29).

0
Robin A. Meade