Auffüllen von Unicode-Strings mit Bashs printf

Sep 13 2020

Ich habe versucht, eine Unicode-Zeichenfolge mit Bashs printf aufzufüllen, und habe das währenddessen gesehen

printf "%2s" a

ergibt das erwartete "a",

eine Unicode-Variante

printf "%2s" ä  

ergibt ein überraschend ungepolstertes "ä". (zsh gibt das erwartete Ergebnis an.)

Was verursacht das? und wie soll ich Unicode-Strings in Bash auffüllen?

Antworten

crackpot Sep 13 2020 at 00:02

Wie soll ich Unicode-Strings in Bash auffüllen?

Das geht weit über die Möglichkeiten von Bash hinaus. Wenn Sie "Unicode-Zeichenfolgen" auf ASCII ++ beschränken (keine Zeichen mit doppelter Breite, kein Bidi, keine Markierungen ohne Abstand, keine usw.), können Sie Folgendes wie folgt beurteilen:

% pad(){ printf '%*s%s\n' "$(($1-${#2}))" "" "$2"; }
% pad 2 €
 €
Quasímodo Sep 13 2020 at 00:06

Das Zeichen äwird in UTF-8 mit 2 Bytes codiert, daher nimmt Printf es für 2-aufgefüllt.

Wc kann die Zeichen ( -m) und Bytes ( -c) einer Zeichenfolge zählen. Die Nummer, die Printf geben soll, ist dann [intended pad]+[bytes]-[chars]. Also habe ich dieses pad.shSkript zusammengestellt,

#!/bin/sh
bytes=$(printf '%s' "$2" | wc -c)
chars=$(printf '%s' "$2" | wc -m)
n=$(($1+bytes-chars))
printf "%${n}s" "$2"

In der folgenden Beispielausführung habe ich aus Gründen der Übersichtlichkeit nach jeder Ausgabe künstlich Zeilenumbrüche hinzugefügt.

$ sh pad.sh 10 abcdef abcdef $ sh pad.sh 10 äéßôçÈ
    äéßôçÈ
schily Sep 12 2020 at 23:48

Bash verhält sich korrekt und das C-Programm

#include <stdio.h>
main()
{
        char foo[] = "ä";

        printf("%2s\n", foo);
}

verhält sich gleich.

Dies liegt daran, dass% s auf eine byteorientierte Zeichenfolge verweist und 'ä' in UTF-8 zu 2 Bytes führt.

Soweit ich testen konnte, verhält sich keine der anderen Schalen falsch.

Das erwartete Ergebnis kann mit folgenden Ergebnissen erzielt werden:

printf '%2S\n' ä

Dies wird jedoch von keiner der von mir getesteten Shells unterstützt.