Relleno de cadenas unicode con printf de bash
Intenté rellenar una cadena Unicode con printf de bash, y lo vi, mientras
printf "%2s" a
produce la "a" esperada,
una variante Unicode
printf "%2s" ä
produce una "ä" sorprendentemente sin relleno. (zsh da el resultado esperado).
Qué causa esto; y ¿cómo se supone que debo rellenar cadenas Unicode en bash?
Respuestas
¿Cómo se supone que debo rellenar cadenas Unicode en bash?
Eso está mucho más allá de las capacidades de bash. Si está limitando las "cadenas Unicode" a ascii ++ (sin caracteres de doble ancho, sin bidi, sin marcas sin espaciado, sin etc.), puede montar como jurado algo como:
% pad(){ printf '%*s%s\n' "$(($1-${#2}))" "" "$2"; }
% pad 2 €
€
El carácter äestá codificado con 2 bytes en UTF-8, por lo que Printf lo toma por 2 rellenos.
Wc puede contar los caracteres ( -m) y bytes ( -c) de una cadena. El número para darle a Printf es entonces [intended pad]+[bytes]-[chars]. Así que reuní este pad.shscript
#!/bin/sh
bytes=$(printf '%s' "$2" | wc -c)
chars=$(printf '%s' "$2" | wc -m)
n=$(($1+bytes-chars))
printf "%${n}s" "$2"
En la ejecución de ejemplo a continuación, he agregado artificialmente nuevas líneas después de cada salida para mayor claridad.
$ sh pad.sh 10 abcdef abcdef $ sh pad.sh 10 äéßôçÈ
äéßôçÈ
bash se comporta correctamente y el programa C
#include <stdio.h>
main()
{
char foo[] = "ä";
printf("%2s\n", foo);
}
se comporta igual.
Esto se debe a que% s se refiere a una cadena orientada a bytes y 'ä' en UTF-8 da como resultado 2 bytes.
Por lo que pude probar, ninguno de los otros proyectiles se comporta incorrectamente.
El resultado que espera se puede ver con algo como:
printf '%2S\n' ä
pero esto no es compatible con ninguno de los shells que probé.