U + xxxxx kodu ile belirtilen ifadeyi utf-8'e nasıl dönüştürebilirim?


16

İfadeler,
her x'in onaltılık bir basamak olduğu bir U + xxxxx biçimi kullanılarak belirtilmiş gibi görünür.

Örneğin, U + 1F615 olan resmi Unicode Konsorsiyumu kodu "şaşkın yüzü" için 😕

Sık sık kafam karıştığından, bu sembol için güçlü bir yakınlığım var.

U +, 1F615 I Unicode karakterleri için olası tek kodlamalar 8, 16, 24 ya da 32 bit gerekli düşünülmektedir, çünkü 5 heks basamak 5x4 = 20 bit gerektirir, oysa bir temsilidir, bana kafa karıştırıcı.

Ben bu sembol bash tamamen farklı bir hex dize ile temsil gibi görünüyor keşfettim:

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

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

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

Ben umuyordum U + 1F615 gibi bir şey dönüştürmek \ x00 \ x01 \ xF6 \ x15 .

Bu 2 kodlama arasındaki ilişkiyi görmüyorum?

Resmi Unicode Konsorsiyumu listesinde bir sembol aradığımda, bu kodu manuel olarak bu sıkıcı bir şekilde dönüştürmek zorunda kalmadan doğrudan kullanabilmek istiyorum. yani

  • bazı web sayfalarındaki sembolü bulma
  • web tarayıcısının panosuna kopyalamak
  • GERÇEK kodunu keşfetmek için bir hexdump ile yankılamak için bash'a yapıştırarak.

Bu 20 bitlik kodu 32 bitlik kodun ne olduğunu belirlemek için kullanabilir miyim?

Bu 2 sayı arasında bir ilişki var mı?

Yanıtlar:


20

UTF-8Unicode değişken uzunluklu kodlamasıdır . ASCII'nin üst kümesi olacak şekilde tasarlanmıştır. Kodlamanın ayrıntıları için Wikipedia'ya bakın . \x00 \x01 \xF6 \x15olabilir UCS-4BEveya UTF-32BEkodlayabilir.

Unicode kod noktasından UTF-8 kodlamasına ulaşmak için, yerel ayarın charmap'in UTF-8 (çıktısına bakın locale charmap) olduğunu varsayarsak, sadece:

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

İkincisi , POSIX standardının bir sonraki sürümünde olacaktır .

AFAIK, bu sözdizimi tek başına GNU tarafından 2000 yılında tanıtıldı printf(aksine fayda printfgetirilen GNU kabuğunun fayda), echo/ printf/ $'...'ilk yerleşikleri tarafından zsh2003 yılında olsa 2010 yılında, 2004 yılında ksh93, bash ( düzgün orada çalışmıyor 2014'e kadar ), ancak diğer dillerden açıkça ilham aldı.

ksh93printf '\x1f615\n've gibi destekler printf '\u{1f615}\n'.

$'\uXXXX've $'\UXXXXXXXX'desteklediği zsh, bash, ksh93, mkshve FreeBSD sh, GNU printf, GNU echo.

Bazıları tüm rakamları gerektirir ( \U0001F615aksine \U1F615) gelecekteki sürümlerde değişebilir, çünkü POSIX daha az basamağa izin verecektir. Her halükarda, tüm haneleri ihtiyaç \UXXXXXXXXolduğu gibi onaltılık rakam takip edilecek \U0001F615FOXgibi \U1F615FOXolurdu $'\U001F615F'OX.

Bazıları, dizenin ayrıştırıldığı veya genişletildiği sırada geçerli yerel ayarın kodlamasındaki karakterlere genişler, bazıları ise yerel ayardan bağımsız olarak yalnızca UTF-8'de. Karakter geçerli yerel ayarın kodlamasında yoksa, davranış kabuklar arasında değişiklik gösterir.

Bu nedenle, en iyi taşınabilirlik için, en iyisi onu yalnızca UTF-8 yerel ayarlarında kullanmak ve tüm rakamları kullanmak ve içinde kullanmaktır $'...':

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

Bunu not et:

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

veya:

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

(Dahil tüm kabukları ile çalışmaz bashçünkü) $'\U0001F615'olduğu ayrıştırılır önce LC_ALLatanır. (ayrıca bir sistemin yerel ayarına sahip olacağının garantisi olmadığını unutmayın C.UTF-8)

İhtiyacınız olan:

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

Veya:

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

(bileşik komut veya işlev içinde değil).


Tersi olarak, UTF-8 kodlamasından Unicode kod noktasına ulaşmak için şu diğer soruya veya o soruya bakın .

$ 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
Dikkat edin \U1F615 sonra başka bir geçerli onaltılık rakam izler farz edilecektir kaçış dizisinin parçası olmak. Takip ettiği şeyden bağımsız olarak çalışmasını sağlamak için, tam sekiz basamak uzunluğunda olmak için yeterli önde gelen sıfırlara sahip olması gerekir:\U0001F615
kasperd

@kasperd, teşekkürler. Evet, kayda değer. Bunu cevaba ekledim.
Stéphane Chazelas

7

İşte UTF-32'den (büyük endian) UTF-8'e dönüştürmenin bir yolu

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

0x01F615Orada onaltılık değerinizi fark edeceksiniz, 32 bit doldurmak için ekstra bir 0 önde.

UTF-8'deki Wikipedia sayfası, bir Unicode kod noktasından UTF-8 temsiline dönüşümü çok açık bir şekilde açıklamaktadır. Ancak bunu kabuk komut dosyasında kendiniz yapmaya çalışmak en iyi fikir olmayabilir.

UTF-32 sabit genişliktedir ve kod noktası ile UTF-32 gösterimi arasındaki yazışma önemsizdir - değer aynıdır.


6

Kafanızda veya kağıt üzerinde yapmanın güzel bir yolu:

  1. Kaç bayt olacağını belirleyin: U + 0080 altındaki değerler bir bayt, U + 0800 altındaki değerler 2 bayt, U + 10000 altındaki değerler 3 bayt, diğer 4 bayttır. Sizin durumunuzda, 4 bayt.

  2. Hex'i sekizlik biçime dönüştürün: 0373025 .

  3. Sonunda başlayarak, her seferinde 2 sekizlik kapalı sıyırma sekizlik değerlerinin bir dizisini elde etmek için: 037 030 025.

  4. Eğer bayt beklenen sayısı daha az sekizli değerleri varsa, başında bir ekstra 0 ekleyin: 000 037 030 025.

  5. Tüm ancak ilk için eklemek 0200almak için: 000 0237 0230 0225.

  6. İlk için, eklemek 0300beklenen uzunluğu 2 ise, 0340durum 3 veya eğer 0360o 4 ise, elde etmek: 360 0237 0230 0225.

Şimdi sekizlik çıkışlı bir dize olarak yazma: \360\237\230\225. İsteğe bağlı olarak onaltılık biçime dönebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.