Remplir les chaînes Unicode avec le printf de Bash
J'ai essayé de remplir une chaîne Unicode avec le printf de bash, et j'ai vu cela, tout en
printf "%2s" a
donne le "a" attendu,
une variante Unicode
printf "%2s" ä
donne un "ä" étonnamment non rembourré. (zsh donne le résultat attendu.)
Qu'est-ce qui cause cela? et comment suis-je censé remplir des chaînes Unicode dans bash?
Réponses
comment suis-je censé remplir des chaînes Unicode dans bash?
C'est bien au-delà des capacités de bash. Si vous limitez les "chaînes Unicode" à ascii ++ (pas de caractères double largeur, pas de bidi, pas de marques sans espacement, pas, etc.), vous pouvez faire quelque chose comme:
% pad(){ printf '%*s%s\n' "$(($1-${#2}))" "" "$2"; }
% pad 2 €
€
Le caractère äest encodé avec 2 octets en UTF-8, donc Printf le prend pour 2-padded.
Wc peut compter les caractères ( -m) et octets ( -c) d'une chaîne. Le numéro à donner à Printf est alors [intended pad]+[bytes]-[chars]. J'ai donc assemblé ce pad.shscript,
#!/bin/sh
bytes=$(printf '%s' "$2" | wc -c)
chars=$(printf '%s' "$2" | wc -m)
n=$(($1+bytes-chars))
printf "%${n}s" "$2"
Dans l'exemple d'exécution ci-dessous, j'ai ajouté artificiellement des nouvelles lignes après chaque sortie pour plus de clarté.
$ sh pad.sh 10 abcdef abcdef $ sh pad.sh 10 äéßôçÈ
äéßôçÈ
bash se comporte correctement et le programme C
#include <stdio.h>
main()
{
char foo[] = "ä";
printf("%2s\n", foo);
}
se comporte de la même manière.
Ceci est dû au fait que% s fait référence à une chaîne orientée octet et que «ä» en UTF-8 donne 2 octets.
Autant que j'ai pu tester, aucun des autres obus ne se comporte de manière incorrecte.
Le résultat que vous attendez peut être vu avec quelque chose comme:
printf '%2S\n' ä
mais cela n'est pris en charge par aucun des shells que j'ai testés.