Dalam bash, bagaimana saya bisa mengubah Unicode Codepoint [0-9A-F] menjadi karakter yang dapat dicetak?


23

Saya memiliki daftar titik kode Unicode, tetapi saya tidak tahu cara "sederhana" untuk mengubah nilai hex ini menjadi karakter aktual yang mereka wakili ...

Saya pernah mendengar bahwa zsh memiliki echo -e '\u0965', tetapi saya menggunakan bash 4.1.

Apakah ada sesuatu yang sederhana seperti metode zsh, untuk bash?


Jawaban:


16

Anda dapat menggunakan gema bash atau / bin / echo dari GNU coreutils dalam kombinasi dengan iconv:

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

Secara default, ikon dikonversi ke penyandian lokal Anda. Mungkin lebih portabel daripada mengandalkan shell atau perintah echo tertentu adalah Perl. Hampir semua sistem UNIX yang saya ketahui memiliki Perl dan bahkan memiliki beberapa port Windows.

perl -C -e 'print chr 0x0965'

Sebagian besar waktu ketika saya perlu melakukan ini, saya berada di editor seperti Vim / GVim yang memiliki dukungan bawaan. Saat dalam mode insert, tekan Ctrl-V diikuti oleh u, lalu ketikkan empat karakter hex. Jika Anda menginginkan karakter di luar U + FFFF, gunakan huruf kapital U dan ketik 8 karakter hex. Vim juga mendukung custom keymaps yang mudah dibuat. Itu mengubah serangkaian karakter ke simbol lain. Sebagai contoh, saya punya keymap yang saya kembangkan bernama www, itu mengubah TM ke ™, (C) ke ©, (R) ke ®, dan seterusnya. Saya juga punya peta kunci untuk Klingon ketika itu menjadi perlu. Saya yakin Emacs memiliki sesuatu yang serupa. Jika Anda berada di aplikasi GTK + yang mencakup GVim dan Terminal GNOME, Anda dapat mencoba Control-Shift-u diikuti oleh 4 karakter hex untuk membuat karakter Unicode. Saya yakin KDE / Qt memiliki sesuatu yang serupa.

UPDATE: Pada Bash 4.2, tampaknya fitur bawaan sekarang:

echo $'\u0965'

UPDATE: Juga, saat ini contoh Python mungkin akan lebih disukai daripada Perl. Ini berfungsi di Python 2 dan 3:

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

Terima kasih ... perl satu di bagus dan singkat, tetapi saya agak bingung bagaimana ia tahu memperlakukan nilai sebagai UTF-16BE .. Saya kira itulah arti "chr" artinya ...
Peter.O

@ Fred, itu poin yang bagus. Contoh Perl sensitif lokal. -C memungkinkan pemrosesan Unicode penuh, tetapi contohnya berfungsi karena lokal saya menggunakan contoh Unicode. Jika saya mengatur LANG ke C, saya mendapat peringatan tentang karakter lebar dalam cetakan, tetapi masih dicetak. Jika saya mencetak chr 0xa2di lokal UTF-8 saya mendapat tanda sen ¢, tetapi jika saya menggunakan LANG = C, saya mendapatkan karena mencetak byte 0xa2 yang tidak valid di UTF-8. Contoh Vim / GVim semi sensitif terhadap lokal. Lebih tepatnya, ke penyandian file. Jika Anda memulai Vim di lokal non-UTF-8, Anda perlu:set encoding=utf-8
penguin359

@ Fred Saya harus menunjukkan, Perl memperlakukan nilai chr sebagai Unicode codepoint jika Perl dimulai di lokal Unicode seperti UTF-8. Codepoint adalah angka unik yang mewakili karakter dan tidak terikat pada salah satu pengkodean seperti UTF-16BE atau UTF-8. Ini mengubahnya menjadi pengkodean yang benar ketika mencetaknya. Misalnya, Cuneiform Sign A adalah codepoint U + 012000. Saya dapat menggunakan chr 0x12000di Perl (dengan asumsi Unicode aktif) untuk mewakilinya. Di UTF-16BE, ini adalah 0xd8, 0x08, 0xdc, dan 0x00. Karakter Anda adalah U + 0965 yang kebetulan merupakan byte 0x09 diikuti oleh 0x65 di UTF-16BE.
penguin359

@ penguin359 .. Terima kasih, suatu hari (semoga) saya akan melihat perl dengan baik .. Tampaknya samar-samar samar, tapi kemudian begitu juga sed dan regex, awalnya, dan sekarang cukup mudah ... mungkin itu sedikit seperti vim; kurva pembelajaran yang curam, lalu berlayar .... Baik untuk membaca penjelasan Anda ... membuka jalan ..
Peter.O

Saya baru saja menemukan bahwa printtion soul Steven D tidak akan menangani blok ASCII dari kisaran unicode, jadi perljawaban Anda sekarang adalah yang terbaik (untuk persyaratan khusus saya) .. Saya sebelumnya mengesampingkan printf (bulan lalu) , tapi aku sudah lupa tentang itu. Inilah pertanyaannya / jawab tentang batasannya ... Mengapa printf melaporkan kesalahan pada semua kecuali tiga (ASCII-range) Unicode Codepoints
Peter.O

13

Bash 4.2 (dirilis pada 2011) menambahkan dukungan untuk echo -e '\u0965', printf '\u0965', printf %b '\u0965'dan echo $'\u0965'juga bekerja.

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

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

Terima kasih ... Saya masih menggunakan bash 4.1.5 di Ubuntu 10.04, tetapi tentu baik mengetahui bahwa sekarang tersedia di 4.2. (+1)
Peter.O

1
+1; perhatikan bahwa bash 4.2.xversi memiliki bug di mana nilai antara 0x80dan 0xff( 128 - 255) - yaitu, dalam rentang ASCII yang diperluas - TIDAK dikodekan dengan benar UTF8 dan alih-alih hanya dilewati, menghasilkan karakter UTF8 yang tidak valid yang beberapa terminal render sebagai ?. Pada (setidaknya) 4.3.11ini telah diperbaiki; jika echo $'\ued'dirender í, maka bug tidak ada.
mklement0

5

Jika Anda memiliki GNU coreutils, coba printf:

$ printf '\u0965\n'

echo dapat melakukan pekerjaan jika konsol Anda menggunakan UTF-8 dan Anda memiliki pengkodean UTF-8:

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

Anda dapat menemukan tabel Unicode ke UTF-8 hex encodings di sini: http://www.utf8-chartable.de/ . Anda dapat mengonversi poin kode Unicode ke hex menggunakan sejumlah bahasa scripting. Berikut ini contoh menggunakan python:

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

Berikut ini adalah skrip Perl yang akan mengonversi argumen ke nilai hex yang benar (banyak tanda kurung yang tidak perlu di sini):

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

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

Contohnya,

./uni2utf 0965
e0a5a5

Tentu saja, jika Anda menggunakan Perl atau Python, Anda juga bisa menggunakannya untuk mencetak karakter.


Terima kasih .. Tidak echoakan melakukan apa yang saya inginkan, karena Codepoint adalah 2-byte UTF-16 Big-Endian .. tetapi Anda telah mengingatkan saya bahwa ada 2 fungsi printf! (Saya pikir printf bisa melakukannya, dan sepertinya saya salah menggunakan) ... $(which printf)berfungsi ... Terima kasih untuk contoh python .. tetapi untuk ini (kurva pembelajaran saya), saya mencoba untuk tetap sedekat mungkin mungkin untuk "bash" sebagai satu-satunya bahasa penulisan yang terlibat .. (ketika saya cukup nyaman dengan bash, saya akan terjebak ke Python ... btw, .encode('hex')adalah satu langkah di luar apa yang saya butuhkan .. (saya pikir itu tampak agak sibuk di sana :)
Peter.O

Ya, .encode ('hex') hanya untuk mendapatkan kode hex yang sepertinya berfungsi dengan gema untuk saya. Senang bahwa setidaknya sebagian dari ini bermanfaat.
Steven D

Saya baru saja melihat Anda perl snippet .. terima kasih ... ada baiknya memiliki berbagai solusi ini diajukan ... Yang printf adalah persis apa yang saya cari (satu perintah, sesuai contoh zsh) ... .. Saya mungkin memposting metode bahasa scripting tidak menggunakan yang lain yang bekerja pada aliran data hex (no \ u, dll) ..
Peter.O

Saya terutama suka singkatnya di printfatas, tetapi tidak menangani nilai-nilai di bawah ini `` perl ... 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* u solusi ` terlihat cukup bagus sekarang :) .. Ini adalah invocaton tunggal, dan saya setelah" mudah mengetik ", jadi saya akan memberikan centang hijau untukperl
Peter.O

2

UPDATE: Ini adalah cara bash untuk melakukan nilai Unicode tunggal ... (dengan "bash" Maksud saya: tidak menggunakan bahasa scripting lain) .. terima kasih kepada Gilles untuk saran pada Q / A askubuntu ini .
Menurut tautan ini : recode (Obsoletes iconv, dos2unix, unix2dos) .. Edit: tetapi sesuai komentar di bawah ini, "obsoletes 'bisa berarti" alternatif "

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

Berikut adalah metode untuk memproses dump hex mentah sebagai input (mis. Tidak ada awalan lolos seperti; \ u0965, dan no \ x09 \ x65) ..
xxdadalah utilitas hex-dump (dikemas dengan vim-common) yang dapat mengembalikan dump hex mentah untuk karakter yang diwakili oleh dump ... Unicode Codepoints adalah UTF-16BigEndian, yang merupakan dump Hex-sebenarnya ..
xxddalam mode revert menerima aliran nilai-nilai Hex dengan jeda baris. yang diabaikan.

Script ini menciptakan aliran UTF-16BE, yang kemudian kembali ke karakter aslinya.
Baris terakhir berisi dua perintah yang dibutuhkan; xxddaniconv

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

Ini adalah output (pertama-tama menunjukkan input hex-dump UTF-16BE).
Catatan; xxdsegmen output sendiri dengan baris baru di 60 hex-digit ... Opsi revert mengabaikan baris baru ini .. itu mengabaikan semua / semua baris baru (karena bukan hex-digit) ..

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

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

Karena tampaknya Anda menggunakan informasi penguin359 dalam jawaban Anda, Anda dapat mempertimbangkan menandai jawabannya sebagai benar daripada milik saya.
Steven D

@ Sebelas D: komentar yang patut dicatat, tetapi "sepertinya" adalah kata operatif. Saya telah menggunakan iconv seperti ini selama beberapa hari sekarang, yang membuat saya bertanya-tanya apakah ada satu perintah. Saya sudah melakukan pemrosesan seluruh file serupa di windows (C ++), jadi saya punya pemahaman reasonlabe tentang Unicode. Saya benar-benar mengejar metode yang cepat dan sederhana bash. Maksud saya "bash": menggunakan bahasa scripting bash; bukan python / perl dari dalam bash). Saya menambahkan ini sebagai jawaban karena mungkin ada nilainya bagi seseorang yang membaca halaman ini. Ini bagus satu-liner untuk seluruh file. Anda printfadalah jawaban terbaik untuk saya.
Peter.O

2
Saya tidak akan mengatakan recode obsoletes iconv, sebenarnya recode lebih tua dari iconv, dan hari ini iconv jauh lebih umum diinstal secara default daripada recode (misalnya, di Linux, iconv hampir selalu diinstal karena dilengkapi dengan libc).
Gilles 'SANGAT berhenti menjadi jahat'

Terima kasih .. Saya bertanya-tanya tentang itu .. Halaman web itu bukan referensi definitif ... jadi lebih merupakan alternatif ...
Peter.O

1

Dengan asumsi pengkodean default untuk OS Anda adalah UTF-8 (berlaku untuk sebagian besar distro terkini) maka Anda dapat menggunakan bash secara langsung untuk mengonversi titik kode UNICODE:

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

Tentu saja, mesin terbang akan muncul dengan benar hanya jika Anda memiliki font yang benar. Pada bash 4.3 semua poin kode akan berfungsi dengan benar. Dan dua opsi bawaan ini juga akan berfungsi:

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

Perhatikan bahwa untuk bash 4.2 kode Unicode menunjuk dari 0x80ke 0xFFdikodekan secara salah (bug bash). Untuk mengatasi masalah ini, Anda harus melihat program di situs ini (juga bagus untuk melihat lebih dalam tentang masalah konversi angka menjadi karakter.


Bekerja untuk saya di bash 4.3 dan zsh. Apakah ada laporan bug untuk bash 4.2 yang dapat Anda tautkan?
Mikel

menurut saya ini seperti bug yang benar: https://lists.gnu.org/archive/html/bug-bash/2012-02/msg00035.htmlDeskripsi: \ u dan \ U salah mengkodekan nilai antara \ u80 dan \ uff

0

Menggunakan substitusi Pola di bash versi 4.2 (dan lebih tinggi):

${parameter/pattern/string}

seperti yang dijelaskan di sini 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
Perhatikan bahwa, sebagaimana dinyatakan dalam jawaban sebelumnya , ini hanya berfungsi dalam versi bash 4.2 (dan lebih tinggi). Faktanya, ini menambahkan sedikit ke jawaban sebelumnya.
G-Man Mengatakan 'Reinstate Monica'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.