Bashのprintfを使用してUnicode文字列を埋める

Bashのprintfを使用してUnicode文字列を埋める

私はbashのprintfでUnicode文字列を埋めようとし、これを見ました。

printf "%2s" a

予想される「a」を生成します。

Unicodeバリアント

printf "%2s" ä  

驚くほど満たされていない「ä」を生成します。 (zshは期待される結果を提供します。)

この問題の原因は何ですか? bashでUnicode文字列をどのように入力しますか?

答え1

文字はä2バイトを使用してUTF-8でエンコードされるため、Printfはそれを2パディングとして扱います。

-mWcは文字列の文字()とバイト()を計算できます。-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 äéßôçÈ
    äéßôçÈ

答え2

BashでUnicode文字列をどのように入力しますか?

これはbashの機能をはるかに超えています。 「Unicode文字列」をascii ++に制限する場合(2バイト文字なし、bidiなし、空白以外のマーカーなしなど)、一時的に次のように設定できます。

% pad(){ printf '%*s%s\n' "$(($1-${#2}))" "" "$2"; }
% pad 2 €

答え3

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

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

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

行動は同じです。

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

私がテストした限り、他のシェルは間違って動作しませんでした。

必要な結果は次のように確認できます。

printf '%2S\n' ä

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

関連情報