Заполнение строк Unicode с помощью printf bash

Sep 13 2020

Я попытался дополнить строку Unicode с помощью printf bash и увидел это, в то время как

printf "%2s" 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, поэтому Printf принимает его как заполненный двумя байтами.

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' ä

но это не поддерживается ни одной из протестированных мною оболочек.