Bagaimana cara mengubah emotikon yang ditentukan oleh kode U + xxxxx ke utf-8?


16

Emoticon tampaknya ditentukan menggunakan format U + xxxxx
dimana masing-masing x adalah digit heksadesimal.

Misalnya, U + 1F615 adalah kode Konsorsium Unicode resmi untuk "wajah bingung" πŸ˜•

Karena saya sering bingung, saya memiliki ikatan yang kuat dengan simbol ini.

The U + 1F615 representasi membingungkan untuk saya karena saya pikir satu-satunya pengkodean mungkin untuk karakter unicode diperlukan 8, 16, 24 atau 32 bit, sedangkan 5 digit hex membutuhkan 5x4 = 20 bit.

Saya telah menemukan bahwa simbol ini tampaknya diwakili oleh string hex yang sama sekali berbeda di bash:

$echo -n πŸ˜• | hexdump
0000000 f0 9f 98 95                                    
0000004

$echo -e "\xf0\x9f\x98\x95"
πŸ˜•

$PS1=$'\xf0\x9f\x98\x95  >'
πŸ˜•  >

Saya mengharapkan U + 1F615 untuk dikonversi ke sesuatu seperti \ x00 \ x01 \ xF6 \ x15 .

Saya tidak melihat hubungan antara 2 penyandian ini?

Ketika saya mencari simbol di daftar Konsorsium Unicode resmi , saya ingin dapat menggunakan kode itu secara langsung tanpa harus mengonversi secara manual dengan cara yang membosankan ini. yaitu

  • menemukan simbol di beberapa halaman web
  • menyalinnya ke clipboard browser web
  • menempelkannya di bash untuk menggema melalui hexdump untuk menemukan kode NYATA.

Bisakah saya menggunakan kode 20-bit ini untuk menentukan apa kode 32-bit itu?

Apakah ada hubungan antara 2 angka ini?

Jawaban:


20

UTF-8adalah pengodean panjang variabel Unicode. Ini dirancang untuk menjadi superset ASCII. Lihat Wikipedia untuk detail enkode. \x00 \x01 \xF6 \x15akan menjadi UCS-4BEatau UTF-32BEpengkodean.

Untuk mendapatkan dari titik kode Unicode ke pengkodean UTF-8, dengan asumsi charmap lokal adalah UTF-8 (lihat output dari locale charmap), itu hanya:

$ printf '\U1F615\n'
πŸ˜•
$ echo -e '\U1F615'
πŸ˜•
$ confused_face=$'\U1F615'

Yang terakhir akan berada di versi standar POSIX berikutnya .

AFAIK, sintaks yang diperkenalkan pada tahun 2000 oleh berdiri sendiri GNU printfutilitas (yang bertentangan dengan printfutilitas dari GNU shell), dibawa ke echo/ printf/ $'...'builtin pertama oleh zshpada tahun 2003 , ksh93 pada tahun 2004, bash pada tahun 2010 (meskipun tidak bekerja dengan benar ada sampai 2014 ), tetapi jelas terinspirasi oleh bahasa lain.

ksh93juga mendukungnya sebagai printf '\x1f615\n'dan printf '\u{1f615}\n'.

$'\uXXXX'dan $'\UXXXXXXXX'didukung oleh zsh, bash, ksh93, mkshdan FreeBSD sh, GNU printf, GNU echo.

Beberapa memerlukan semua digit (seperti yang \U0001F615bertentangan \U1F615) meskipun itu kemungkinan akan berubah di versi masa depan karena POSIX akan memungkinkan lebih sedikit digit. Bagaimanapun, Anda membutuhkan semua digit jika \UXXXXXXXXakan diikuti oleh digit heksadesimal seperti pada \U0001F615FOX, seperti yang \U1F615FOXseharusnya $'\U001F615F'OX.

Beberapa memperluas ke karakter dalam pengkodean lokal saat ini pada saat string diuraikan atau pada saat itu diperluas, beberapa hanya di UTF-8 terlepas dari lokal. Jika karakter tidak tersedia di pengkodean lokal saat ini, perilaku bervariasi antara shell.

Jadi, untuk portabilitas terbaik, yang terbaik adalah hanya menggunakannya di lokal UTF-8 dan gunakan semua digit, dan gunakan di $'...':

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

Perhatikan bahwa:

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

atau:

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

Tidak akan bekerja dengan semua kerang (termasuk bash) karena $'\U0001F615'ini diurai sebelum LC_ALLditugaskan. (juga perhatikan bahwa tidak ada jaminan bahwa suatu sistem akan memiliki lokal yang disebut C.UTF-8)

Anda membutuhkan:

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

Atau:

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

(tidak dalam perintah majemuk atau fungsi).


Untuk kebalikannya, untuk mendapatkan dari pengkodean UTF-8 ke titik kode Unicode, lihat pertanyaan lain ini atau itu .

$ 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
Perhatikan bahwa jika \U1F615diikuti oleh digit heksadesimal lain yang valid maka itu akan dianggap sebagai bagian dari urutan escape. Untuk membuatnya bekerja terlepas dari apa yang diikuti oleh itu, harus memiliki cukup nol mengarah tepat tepat delapan digit:\U0001F615
kasperd

@kasperd, terima kasih. Ya, perlu diperhatikan. Saya sudah memasukkan itu dalam jawabannya.
StΓ©phane Chazelas

7

Berikut cara untuk mengkonversi dari UTF-32 (big endian) ke UTF-8

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

Anda akan melihat nilai hex Anda 0x01F615di sana, diisi dengan 0 terkemuka ekstra untuk mengisi 32 bit.

Halaman Wikipedia di UTF-8 menjelaskan transformasi dari titik kode Unicode ke representasi UTF-8 dengan sangat jelas. Tetapi mencoba melakukannya sendiri dalam skrip shell mungkin bukan ide terbaik.

UTF-32 adalah fixed-width, dan korespondensi antara codepoint dan representasi UTF-32 adalah sepele - nilainya sama.


6

Cara yang bagus untuk melakukannya di kepala atau di atas kertas:

  1. Cari tahu berapa banyak byte yang akan dihasilkan: nilai di bawah U + 0080 adalah satu byte, jika tidak di bawah U + 0800 adalah 2 byte, selain itu di bawah U + 10000 adalah 3 byte, atau 4 byte. Dalam kasus Anda, 4 byte.

  2. Convert hex ke oktal: 0373025.

  3. Mulai di akhir, peel off 2 oktal digit pada suatu waktu untuk mendapatkan urutan nilai oktal: 037 030 025.

  4. Jika Anda memiliki nilai oktal lebih sedikit dari jumlah yang diharapkan dari byte, menambahkan ekstra 0 di awal: 000 037 030 025.

  5. Untuk semua tapi yang pertama, menambahkan 0200untuk mendapatkan: 000 0237 0230 0225.

  6. Untuk pertama, tambahkan 0300jika panjang diharapkan adalah 2, 0340jika itu 3, atau 0360jika itu 4, untuk mendapatkan: 360 0237 0230 0225.

Sekarang menulis sebagai string lolos oktal: \360\237\230\225. Secara opsional ubah kembali ke hex jika Anda mau.

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.