In bash, come posso convertire un punto di codice Unicode [0-9A-F] in un carattere stampabile?


Risposte:


16

Puoi usare l'eco di bash o / bin / echo dai coreutils GNU in combinazione con iconv:

echo -ne '\x09\x65' | iconv -f utf-16be

Per impostazione predefinita iconv si converte nella codifica locale. Forse più portatile che fare affidamento su uno specifico comando shell o echo è Perl. Quasi tutti i sistemi UNIX di cui sono a conoscenza mentre Perl è disponibile e ha anche diverse porte di Windows.

perl -C -e 'print chr 0x0965'

Il più delle volte quando ho bisogno di farlo, sono in un editor come Vim / GVim che ha il supporto integrato. In modalità inserimento, premi Ctrl-V seguito da u, quindi digita quattro caratteri esadecimali. Se vuoi un personaggio oltre U + FFFF, usa una U maiuscola e digita 8 caratteri esadecimali. Vim supporta anche keymap personalizzate facili da realizzare. Converte una serie di caratteri in un altro simbolo. Ad esempio, ho una keymap che ho sviluppato chiamato www, converte TM in ™, (C) in ©, (R) in ® e così via. Ho anche una keymap per Klingon per quando sarà necessario. Sono sicuro che Emacs ha qualcosa di simile. Se ti trovi in ​​un'app GTK + che include GVim e GNOME Terminal, puoi provare Control-Shift-u seguito da 4 caratteri esadecimali per creare un carattere Unicode. Sono sicuro che KDE / Qt abbia qualcosa di simile.

AGGIORNAMENTO: A partire da Bash 4.2, sembra essere una funzionalità integrata ora:

echo $'\u0965'

AGGIORNAMENTO: Inoltre, al giorno d'oggi un esempio di Python sarebbe probabilmente preferito a Perl. Funziona con Python 2 e 3:

python -c 'print(u"\u0965")'

Grazie ... il perl è bello e conciso, ma mi ha un po 'perplesso su come sappia trattare il valore come UTF-16BE .. Immagino sia questo che significa "chr" ...
Peter.O

@fred è un buon punto. L'esempio Perl è sensibile alle impostazioni locali. -C abilita l'elaborazione Unicode completa, ma l'esempio funziona perché la mia locale usa un esempio Unicode. Se imposto LANG su C, ricevo un avviso su un carattere largo nella stampa, ma continua a stampare. Se stampo chr 0xa2in una locale UTF-8 ottengo un segno di centesimi ¢, ma se uso LANG = C, ottengo perché stampa il byte 0xa2 che non è valido in UTF-8. L'esempio Vim / GVim è semi-sensibile alla locale. Più correttamente, alla codifica dei file. Se hai avviato Vim in una locale non UTF-8, dovrai farlo:set encoding=utf-8
penguin359

@fred Vorrei sottolineare che Perl considera il valore di chr come un punto di codice Unicode se Perl viene avviato in una locale Unicode come UTF-8. Un punto di codice è il numero univoco che rappresenta un carattere e non è associato a nessuna codifica come UTF-16BE o UTF-8. Lo converte nella codifica corretta quando lo stampa. Ad esempio, il segno cuneiforme A è punto di codice U + 012000. Posso usarlo chr 0x12000in Perl (supponendo che Unicode sia attivo) per rappresentarlo. In UTF-16BE, questo è 0xd8, 0x08, 0xdc e 0x00. Il tuo personaggio è U + 0965 che sembra essere solo i byte 0x09 seguiti da 0x65 in UTF-16BE.
penguin359,

@ penguin359 .. Grazie, un giorno (si spera) darò una buona occhiata al perl .. Sembra insondabilmente criptico, ma poi anche sed e regex, inizialmente, e ora è abbastanza facile ... forse è un po ' come vim; una ripida curva di apprendimento, quindi la semplice navigazione .... È bello leggere la tua spiegazione ... apre la strada ..
Peter.O

Ho appena (ri) scoperto che l' anima printf di Steven D non gestirà il blocco ASCII dell'intervallo unicode, quindi la tua perlrisposta è ora la migliore (per i miei requisiti particolari). In precedenza avevo escluso printf (mesi fa) , ma me ne ero dimenticato. Ecco la queston / risposta sui suoi limiti ... Perché printf segnala un errore su tutti i codepoints Unicode tranne tre (intervallo ASCII)
Peter.O

13

Bash 4.2 (uscito nel 2011) aggiunto il supporto per echo -e '\u0965', printf '\u0965', printf %b '\u0965'e echo $'\u0965'anche il lavoro.

http://tiswww.case.edu/php/chet/bash/FAQ :

o   $'...', echo, and printf understand \uXXXX and \UXXXXXXXX escape sequences.

Grazie ... Sto ancora usando bash 4.1.5 in Ubuntu 10.04, ma è certamente bello sapere che ora è disponibile in 4.2. (+1)
Peter

1
+1; si noti che le bash 4.2.xversioni hanno un bug in cui i valori tra 0x80e 0xff( 128 - 255) - vale a dire, nell'intervallo ASCII esteso - NON sono codificati correttamente UTF8 e invece sono passati, risultando in un carattere UTF8 non valido che alcuni terminali visualizzano come ?. A partire da (almeno) 4.3.11questo è stato risolto; se viene echo $'\ued'eseguito il rendering í, il bug non è presente.
mklement0

5

Se hai coreutils GNU, prova printf:

$ printf '\u0965\n'

echo può fare il lavoro se la tua console utilizza UTF-8 e hai la codifica UTF-8:

$ echo -e '\xE0\xA5\xA5'

È possibile trovare una tabella di codifiche esadecimali da Unicode a UTF-8 qui: http://www.utf8-chartable.de/ . È possibile convertire i punti di codice Unicode in esadecimali utilizzando un numero di linguaggi di scripting. Ecco un esempio usando Python:

python -c "print(unichr(int('0965', 16)).encode('utf-8').encode('hex'))"

Quello che segue è uno script Perl che converte gli argomenti nel valore esadecimale corretto (molte parentesi non necessarie qui):

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Encode;

foreach (@ARGV) {
    say unpack('H*', encode('utf8', chr(hex($_))))
}

Per esempio,

./uni2utf 0965
e0a5a5

Naturalmente, se hai Perl o Python potresti anche usarli per stampare i personaggi.


Grazie .. echoNon farò quello che voglio, poiché i Codepoints sono UTF-16 a 2 byte Big-Endian .. ma mi hai ricordato che ci sono 2 funzioni printf! (Pensavo che printf potesse farlo, e sembra che stia invocando quello sbagliato) ... $(which printf)funziona ... Grazie per l'esempio di Python ... ma per questo (la mia curva di apprendimento), sto cercando di rimanere il più vicino possibile il più possibile "bash" come unico linguaggio di scrittura coinvolto ... (quando mi sentirò abbastanza a mio agio con bash, rimarrò bloccato in Python ... a proposito, .encode('hex')è un passo oltre quello di cui ho bisogno .. un po 'occupato lì dentro :)
Peter.O

Sì, il .encode ('hex') era solo per ottenere il codice hex che sembrava funzionare con l'eco per me. Sono contento che almeno una parte di questo sia stato utile.
Steven D

Ti ho appena visto frammento di perl .. grazie ... è bello avere queste varie soluzioni presentate ... Quello di printf è esattamente quello che stavo cercando (un singolo comando, come nell'esempio zsh) ... .. Potrei pubblicare bene il mio metodo di non usare un altro linguaggio di scripting che funziona su un flusso di dati esadecimali (no \ u, ecc.)
Peter.O

Mi piace in particolare la brevità di quanto printfsopra, ma non gestisce i valori al di sotto della soluzione `` \ u00A0 ... I've just re-discovered something I already knew (but dropped off the radar)... Here is a Question I asked about 4 months ago; [Why does printf report an error on all but three (ASCII-range) Unicode Codepoints](http://askubuntu.com/questions/20806/why-does-printf-report-an-error-on-all-but-three-ascii-range-unicode-codepoints)... So *penguin359's* perl` ora sembra piuttosto buona :) .. È un singolo invocaton, e dopo "facile da scrivere", quindi darò lui il segno di spunta verde perperl
Peter

2

AGGIORNAMENTO: Ecco un modo bash per fare un singolo valore Unicode ... (da "bash" Voglio dire: non utilizzando qualsiasi altro linguaggio di scripting) .. grazie a Gilles per un suggeston in questo Ask Ubuntu Q / A .
Secondo questo link : recode (Obsoletes iconv, dos2unix, unix2dos) .. Modifica: ma secondo il commento qui sotto, "obsoletes" può significare solo "alternativa"

      echo -n 0x0965 |recode UTF-16BE/x4..UTF-8

Ecco un metodo per elaborare un grezzo esadecimale come input (cioè non come-prefissi evase;. \ U0965, e nessun \ x09 \ x65) ..
xxdè un'utilità hex-dump (impaccato con vim-common) che può ripristinare un'immagine esadecimale greggio ai caratteri che il dump rappresenta ... I punti di codice Unicode sono UTF-16BigEndian, che è esattamente ciò che è un dump esadecimale.
xxdIn modalità di ripristino accetta un flusso di valori esadecimali con interruzioni di riga che vengono ignorate.

Questo script crea un flusso UTF-16BE, che poi ripristina ai caratteri originali.
L'ultima riga contiene i due comandi necessari; xxdeiconv

for line in \
  "Matsuo Basho (1644-1694)" \
  "  pond" \
  "  frog jumps in" \
  "  plop!"
do 
  echo "$line" |iconv -f "$(locale charmap)" -t "UTF-16BE" |xxd -ps -u 
done |
#    (---this is the **revert** code---) 
tee >(xxd -p -u -r |iconv -f "UTF-16BE") ;echo

Ecco l'output (che mostra per primo l'ingresso hex-dump UTF-16BE).
Nota; xxdsegmenta il proprio output con una nuova riga a 60 cifre esadecimali ... L'opzione di ripristino ignora queste nuove righe .. ignora qualsiasi / tutte le nuove righe (poiché non sono cifre esadecimali) ..

004D0061007400730075006F00200042006100730068006F002000280031
003600340034002D00310036003900340029000A
002000200070006F006E0064000A
0020002000660072006F00670020006A0075006D0070007300200069006E
000A
002000200070006C006F00700021000A

Matsuo Basho (1644-1694)
  pond
  frog jumps in
  plop!

Dal momento che sembra che tu abbia usato le informazioni di penguin359 nella tua risposta, potresti considerare di contrassegnare la sua risposta come corretta piuttosto che mia.
Steven D,

@Steven D: un commento degno di nota, ma "sembrare" è la parola chiave. Uso iconv in questo modo da un paio di giorni, il che mi ha fatto pensare se esiste un solo comando. Ho eseguito un'elaborazione simile di tutto il file in Windows (C ++), quindi ho una comprensione ragionevole di Unicode. Ero davvero alla ricerca di un bashmetodo rapido e semplice . Con "bash" intendo: usare il linguaggio di scripting bash; non python / perl all'interno di bash). Ho aggiunto questo come una risposta perché potrebbe essere di qualche valore per qualcuno che legge questa pagina. È un buon liner per un intero file. La tua printfè la risposta migliore per me.
Peter

2
Non direi recode obsoletes iconv, in effetti recode è più vecchio di iconv, e oggigiorno iconv è molto più comunemente installato di default rispetto alla ricodifica (ad esempio, su Linux, iconv è quasi sempre installato perché viene fornito con libc).
Gilles 'SO- smetti di essere malvagio'

Grazie .. Me lo stavo chiedendo ... Quella pagina web non è esattamente il riferimento definitivo ... quindi è più un'alternativa ...
Peter.O

1

Supponendo che la codifica predefinita per il tuo sistema operativo sia UTF-8 (vero per la maggior parte delle distribuzioni attuali), puoi utilizzare direttamente bash per convertire qualsiasi punto di codice UNICODE:

echo -e "Unicode Character 'DEVANAGARI DOUBLE DANDA' (U+0965) \U0965"

Naturalmente, il glifo verrà visualizzato correttamente solo se si dispone del carattere corretto. A partire da bash 4.3 tutti i punti di codice funzioneranno correttamente. E queste due opzioni integrate funzioneranno anche:

printf "%b" "Unicode Character (U+0965) \U0965 \n"
echo $'Unicode Character (U+0965) \U0965'

Si noti che per bash 4.2 i punti di codice Unicode da 0x80a 0xFFsono codificati in modo errato (bug bash). Per ovviare a questo problema, è necessario dare un'occhiata al programma in questo sito (utile anche per approfondire il problema della conversione dei numeri in caratteri.


Funziona per me in bash 4.3 e zsh. Esiste una segnalazione di bug per bash 4.2 a cui puoi collegarti?
Mikel,

questo mi sembra il bug corretto: https://lists.gnu.org/archive/html/bug-bash/2012-02/msg00035.htmlDescrizione: \ u e \ U codificano erroneamente i valori tra \ u80 e \ uff

0

Usando la sostituzione Pattern nella versione 4.2 (e successive) di bash:

${parameter/pattern/string}

come descritto qui http://steve-parker.org/sh/tips/pattern-substitution/

UNICODE_HEX="U+02211"
printf ${UNICODE_HEX/U+/"\U"}


UNICODE_HEX="U+03BB"
printf ${UNICODE_HEX/U+/"\U"}
λ         

1
Si noti che, come indicato in una risposta precedente , questo funziona solo nella versione 4.2 di bash (e successive). In realtà, questo aggiunge abbastanza poco alla risposta precedente.
G-Man dice "Ripristina Monica" l'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.