Comment convertir une émoticône spécifiée par un code U + xxxxx en utf-8?


16

Les émoticônes semblent être spécifiées en utilisant un format U + xxxxx
dans lequel chaque x est un chiffre hexadécimal.

Par exemple, U + 1F615 est le code officiel Unicode Consortium pour le "visage confus" 😕

Comme je suis souvent confus, j'ai une forte affinité pour ce symbole.

La représentation U + 1F615 me déroute parce que je pensais que les seuls encodages possibles pour les caractères unicode nécessitaient 8, 16, 24 ou 32 bits, alors que 5 chiffres hexadécimaux nécessitent 5x4 = 20 bits.

J'ai découvert que ce symbole semble être représenté par une chaîne hexadécimale complètement différente dans bash:

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

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

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

Je m'attendais à ce que U + 1F615 se convertisse en quelque chose comme \ x00 \ x01 \ xF6 \ x15 .

Je ne vois pas la relation entre ces 2 encodages?

Lorsque je recherche un symbole dans la liste officielle du Consortium Unicode , j'aimerais pouvoir utiliser ce code directement sans avoir à le convertir manuellement de cette façon fastidieuse. c'est à dire

  • trouver le symbole sur une page Web
  • le copier dans le presse-papiers du navigateur Web
  • le coller dans bash pour faire écho à travers un hexdump pour découvrir le code REAL.

Puis-je utiliser ce code 20 bits pour déterminer quel est le code 32 bits?

Existe-t-il une relation entre ces 2 nombres?

Réponses:


20

UTF-8est un codage de longueur variable d'Unicode. Il est conçu pour être un sur-ensemble d'ASCII. Voir Wikipedia pour plus de détails sur l'encodage. \x00 \x01 \xF6 \x15serait UCS-4BEou UTF-32BEencodage.

Pour passer du point de code Unicode au codage UTF-8, en supposant que le charmap de la locale est UTF-8 (voir la sortie de locale charmap), c'est juste:

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

Ce dernier sera dans la prochaine version du standard POSIX .

Autant que je sache, cette syntaxe a été introduite en 2000 par la GNU autonome printfutilitaire (par opposition à l' printfutilité du shell GNU), amené à echo/ printf/ $'...'builtins premier par zshen 2003 , ksh93 en 2004, bash en 2010 (mais ne fonctionne pas correctement , il jusqu'en 2014 ), mais a évidemment été inspiré par d'autres langues.

ksh93le prend également en charge comme printf '\x1f615\n'et printf '\u{1f615}\n'.

$'\uXXXX'et $'\UXXXXXXXX'sont pris en charge par zsh, bash, ksh93, mkshet FreeBSD sh, GNU printf, GNU echo.

Certains nécessitent tous les chiffres (par \U0001F615opposition à \U1F615), mais cela est susceptible de changer dans les futures versions car POSIX autorisera moins de chiffres. Dans tous les cas, vous avez besoin de tous les chiffres si le \UXXXXXXXXdoit être suivi de chiffres hexadécimaux comme dans \U0001F615FOX, comme \U1F615FOXcela aurait été le cas $'\U001F615F'OX.

Certains se développent aux caractères de l'encodage des paramètres régionaux actuels au moment où la chaîne est analysée ou au moment où elle est développée, certains uniquement en UTF-8, indépendamment des paramètres régionaux. Si le caractère n'est pas disponible dans l'encodage des paramètres régionaux en cours, le comportement varie selon les shells.

Donc, pour une meilleure portabilité, le mieux est de ne l'utiliser que dans les paramètres régionaux UTF-8 et d'utiliser tous les chiffres, et de l'utiliser dans $'...':

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

Notez que:

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

ou:

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

Ne fonctionnera pas avec tous les shells (y compris bash) car le $'\U0001F615'est analysé avant d' LC_ALLêtre attribué. (notez également qu'il n'y a aucune garantie qu'un système aura un paramètre régional appelé C.UTF-8)

Vous auriez besoin de:

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

Ou:

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

(pas dans une commande ou une fonction composée).


Pour l'inverse, pour passer du codage UTF-8 au point de code Unicode, voir cette autre question ou celle-là .

$ 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
Notez que si \U1F615est suivi d'un autre chiffre hexadécimal valide, alors il sera supposé faire partie de la séquence d'échappement. Pour le faire fonctionner, peu importe ce qu'il est suivi, il doit avoir suffisamment de zéros de tête pour être exactement huit chiffres:\U0001F615
kasperd

@kasperd, merci. Oui, ça vaut la peine de le noter. J'ai inclus cela dans la réponse.
Stéphane Chazelas

7

Voici un moyen de convertir UTF-32 (big endian) en UTF-8

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

Vous remarquerez votre valeur hexadécimale 0x01F615, complétée par un 0 supplémentaire pour remplir 32 bits.

La page Wikipédia sur UTF-8 explique très clairement la transformation d'un point de code Unicode en sa représentation UTF-8. Mais essayer de le faire vous-même dans les scripts shell n'est peut-être pas la meilleure idée.

UTF-32 est à largeur fixe et la correspondance entre le codet et la représentation UTF-32 est triviale - la valeur est la même.


6

Belle façon de le faire dans votre tête ou sur papier:

  1. Calculez combien d'octets ce sera: les valeurs sous U + 0080 sont un octet, sinon sous U + 0800 sont 2 octets, sinon sous U + 10000 sont 3 octets, sinon 4 octets. Dans votre cas, 4 octets.

  2. Convertir hex à octal: 0373025.

  3. À partir de la fin, Décollez 2 chiffres octal à la fois pour obtenir une séquence de valeurs octal: 037 030 025.

  4. Si vous avez moins de valeurs que octal le nombre prévu d'octets, ajouter un montant supplémentaire de 0 au début: 000 037 030 025.

  5. Pour tous , mais le premier, ajouter 0200à obtenir: 000 0237 0230 0225.

  6. Pour la première, ajouter 0300si la durée prévue est de 2, 0340si elle est 3, ou 0360si elle est 4, pour obtenir: 360 0237 0230 0225.

Maintenant , écrivez comme une chaîne d'évasions octal: \360\237\230\225. Convertissez éventuellement en hex si vous le souhaitez.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.