bashのprintfでUnicode文字列をパディングする

Sep 13 2020

Unicode文字列にbashのprintfをパディングしてみたところ、それがわかりました。

printf "%2s" a

期待される「a」を生成します。

Unicodeの異体字

printf "%2s" ä  

驚くほどパディングされていない「ä」が生成されます。(zshは期待される結果をもたらします。)

これを引き起こす原因; そして、Unicode文字列をbashで埋めるにはどうすればよいですか?

回答

crackpot Sep 13 2020 at 00:02

Unicode文字列をbashで埋めるにはどうすればよいですか?

それはbashの能力をはるかに超えています。「Unicode文字列」をascii ++(倍幅文字、ビディ、非スペーシングマークなど)に制限している場合は、次のような仮帆装を使用できます。

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

文字äはUTF-8で2バイトでエンコードされるため、Printfでは2バイトになります。

Wcは、文字列の文字(-m)とバイト(-c)をカウントできます。その場合、Printfに与える数は[intended pad]+[bytes]-[chars]です。だから私はこのpad.shスクリプトを組み立てました、

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

以下の実行例では、わかりやすくするために、各出力の後に人為的に改行を追加しています。

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

bashは正しく動作し、Cプログラムは

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

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

同じように動作します。

これは、%sがバイト指向の文字列を参照し、UTF-8の「ä」が2バイトになるためです。

私がテストできる限り、他のシェルはどれも正しく動作しません。

期待する結果は、次のように表示されます。

printf '%2S\n' ä

しかし、これは私がテストしたどのシェルでもサポートされていません。