Wie konvertiere ich ein mit einem U + xxxxx-Code angegebenes Emoticon nach utf-8?


16

Emoticons scheinen mit einem Format von U + xxxxx angegeben zu werden,
wobei jedes x eine hexadezimale Ziffer ist.

Zum Beispiel ist U + 1F615 der offizielle Unicode-Konsortialcode für das "verwirrte Gesicht" 😕

Da ich oft verwirrt bin, habe ich eine starke Affinität zu diesem Symbol.

Die U + 1F615- Darstellung ist für mich verwirrend, da ich dachte, dass die einzigen möglichen Codierungen für Unicode-Zeichen 8, 16, 24 oder 32 Bit erfordern, wohingegen 5 Hexadezimalziffern 5 x 4 = 20 Bit erfordern.

Ich habe festgestellt, dass dieses Symbol in der Bash durch eine völlig andere Hex-Zeichenfolge dargestellt zu werden scheint:

$echo -n 😕 | hexdump
0000000 f0 9f 98 95                                    
0000004

$echo -e "\xf0\x9f\x98\x95"
😕

$PS1=$'\xf0\x9f\x98\x95  >'
😕  >

Ich hätte erwartet, dass U + 1F615 in etwas wie \ x00 \ x01 \ xF6 \ x15 konvertiert .

Ich sehe die Beziehung zwischen diesen beiden Kodierungen nicht?

Wenn ich ein Symbol in der Liste des offiziellen Unicode-Konsortiums suche , möchte ich diesen Code direkt verwenden können, ohne ihn mühsam manuell konvertieren zu müssen. dh

  • Finden des Symbols auf einer Webseite
  • Kopieren in die Zwischenablage des Webbrowsers
  • Einfügen in Bash, um den REAL-Code durch einen Hexdump zu finden.

Kann ich diesen 20-Bit-Code verwenden, um den 32-Bit-Code zu bestimmen?

Besteht eine Beziehung zwischen diesen beiden Zahlen?

Antworten:


20

UTF-8ist eine Codierung mit variabler Länge für Unicode. Es ist so konzipiert, dass es eine Obermenge von ASCII ist. Einzelheiten zur Kodierung finden Sie in Wikipedia . \x00 \x01 \xF6 \x15wäre UCS-4BEoder UTF-32BEKodierung.

Wenn Sie vom Unicode-Codepunkt zur UTF-8-Codierung gelangen möchten, gehen Sie davon aus, dass das Charmap des Gebietsschemas UTF-8 ist (siehe die Ausgabe von locale charmap).

$ printf '\U1F615\n'
😕
$ echo -e '\U1F615'
😕
$ confused_face=$'\U1F615'

Letzteres wird in der nächsten Version des POSIX-Standards enthalten sein .

AFAIK, dass Syntax wurde im Jahr 2000 durch das Stand-alone - GNU eingeführt printfDienstprogramm (im Gegensatz zu dem printfNutzen des GNU - Shell), geholt echo/ printf/ $'...'builtins ersten von zsh2003 , ksh93 2004 bash im Jahr 2010 (wenn auch nicht richtig dort arbeitet bis 2014 ), wurde aber offensichtlich von anderen Sprachen inspiriert.

ksh93unterstützt es auch als printf '\x1f615\n'und printf '\u{1f615}\n'.

$'\uXXXX'und $'\UXXXXXXXX'werden unterstützt von zsh, bash, ksh93, mkshund FreeBSD sh, GNU printf, GNU echo.

Einige erfordern alle Ziffern (im \U0001F615Gegensatz zu \U1F615), obwohl dies in zukünftigen Versionen wahrscheinlich geändert wird, da POSIX weniger Ziffern zulässt. In jedem Fall müssen Sie alle Ziffern , wenn die \UXXXXXXXXdurch hexadezimale Ziffern wie in gefolgt werden soll \U0001F615FOX, wie es \U1F615FOXgewesen wäre $'\U001F615F'OX.

Einige werden zu dem Zeitpunkt, zu dem die Zeichenfolge analysiert wird, oder zu dem Zeitpunkt, zu dem sie erweitert wird, auf die Zeichen in der Codierung des aktuellen Gebietsschemas erweitert, andere nur in UTF-8, unabhängig vom Gebietsschema. Wenn das Zeichen in der Codierung des aktuellen Gebietsschemas nicht verfügbar ist, variiert das Verhalten zwischen den Shells.

Um eine optimale Portabilität zu erzielen, verwenden Sie es am besten nur in UTF-8-Gebietsschemas und verwenden Sie alle Ziffern und verwenden Sie es in $'...':

printf '%s\n' $'\U0001F615'

Beachten Sie, dass:

LC_ALL=C.UTF-8; printf '%s\n' $'\U0001F615'

oder:

{
  LC_ALL=C.UTF-8
  printf '%s\n' $'\U0001F615'
}

Wird nicht mit allen Schalen (einschließlich arbeiten bash) , weil das $'\U0001F615'wird analysiert , bevor LC_ALLzugeordnet ist. (Beachten Sie auch, dass es keine Garantie dafür gibt, dass ein System ein genanntes Gebietsschema hat. C.UTF-8)

Sie brauchen:

LC_ALL=C.UTF-8; eval "confused_face=$'\U0001F615'"

Oder:

LC_ALL=C.UTF-8
printf '%s\n' $'\U0001F615'

(Nicht innerhalb eines zusammengesetzten Befehls oder einer zusammengesetzten Funktion).


Um von der UTF-8-Codierung zum Unicode-Codepunkt zu gelangen, lesen Sie diese oder jene andere Frage .

$ unicode 😕 
U+1F615 CONFUSED FACE
UTF-8: f0 9f 98 95  UTF-16BE: d83dde15  Decimal: 😕
😕
Category: So (Symbol, Other)
Bidi: ON (Other Neutrals)

$ perl -CA -le 'printf "%x\n", ord shift' 😕
1f615

2
Beachten Sie, dass, wenn \U1F615eine andere gültige Hexadezimalzahl folgt, angenommen wird, dass diese Teil der Escape-Sequenz ist. Damit es funktioniert, unabhängig davon, worauf es folgt, muss es genügend führende Nullen haben, um genau acht Stellen lang zu sein:\U0001F615
Kasperd

@kasperd, danke. Ja, es ist erwähnenswert. Ich habe das in die Antwort aufgenommen.
Stéphane Chazelas

7

Hier ist eine Möglichkeit, von UTF-32 (Big Endian) nach UTF-8 zu konvertieren

$ confused=$(echo -ne "\x0\x01\xF6\x15" | iconv -f UTF-32BE -t UTF-8)     
$ echo $confused 
😕

Sie werden dort Ihren Hex-Wert bemerken 0x01F615, der mit einer zusätzlichen führenden 0 aufgefüllt ist, um 32 Bits zu füllen.

Die Wikipedia-Seite zu UTF-8 erklärt die Umwandlung von einem Unicode-Codepunkt in seine UTF-8-Darstellung sehr deutlich. Es ist jedoch möglicherweise nicht die beste Idee, es in Shell-Skripten selbst zu tun.

UTF-32 hat eine feste Breite und die Entsprechung zwischen Codepoint und UTF-32-Darstellung ist trivial - der Wert ist der gleiche.


6

Schöne Art und Weise, es in deinem Kopf oder auf Papier zu tun:

  1. Stellen Sie fest, wie viele Bytes es sein werden: Werte unter U + 0080 sind ein Byte, andere unter U + 0800 sind 2 Bytes, andere unter U + 10000 sind 3 Bytes, andere 4 Bytes. In Ihrem Fall 4 Bytes.

  2. Konvertieren hex zu Oktal: 0373025.

  3. Ab Ende, abschälen 2 Oktalziffern zu einer Zeit , eine Folge von Oktalwerte zu erhalten: 037 030 025.

  4. Wenn Sie weniger Oktalwerte als die erwartete Anzahl von Bytes haben, eine zusätzliche 0 am Anfang hinzufügen: 000 037 030 025.

  5. Für alle , aber die erste, fügen Sie auf 0200bekommen: 000 0237 0230 0225.

  6. Zum ersten, hinzufügen , 0300wenn die erwarteten Länge 2 ist, 0340wenn es 3 ist, oder 0360wenn es 4 ist, zu erhalten: 360 0237 0230 0225.

Schreiben Sie jetzt als eine Reihe von Oktal entkommt: \360\237\230\225. Wenn Sie möchten, können Sie auch zurück in Hex konvertieren.

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.