Đệm chuỗi unicode bằng bash's printf

Sep 13 2020

Tôi đã thử đệm một chuỗi Unicode bằng bash's printf và thấy điều đó, trong khi

printf "%2s" a

mang lại "a" mong đợi,

một biến thể Unicode

printf "%2s" ä  

tạo ra một "ä" không được đánh dấu một cách đáng ngạc nhiên. (zsh cho kết quả mong đợi.)

Điều gì gây ra điều này; và làm thế nào tôi phải đệm các chuỗi Unicode trong bash?

Trả lời

crackpot Sep 13 2020 at 00:02

làm thế nào tôi phải đệm các chuỗi Unicode trong bash?

Đó là cách vượt quá khả năng của bash. Nếu bạn đang giới hạn "chuỗi Unicode" thành ascii ++ (không có ký tự 2 byte, không có bidi, không có dấu không giãn cách, không, v.v.), bạn có thể giám khảo một cái gì đó như:

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

Ký tự äđược mã hóa bằng 2 byte trong UTF-8, vì vậy Printf lấy nó cho 2 dấu đệm.

Wc có thể đếm các ký tự ( -m) và byte ( -c) của một chuỗi. Con số để cung cấp cho Printf sau đó [intended pad]+[bytes]-[chars]. Vì vậy, tôi đã tập hợp pad.shkịch bản này ,

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

Trong ví dụ thực hiện bên dưới, tôi đã thêm các dòng mới một cách nghệ thuật sau mỗi đầu ra để rõ ràng hơn.

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

bash hoạt động chính xác và chương trình C

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

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

cư xử giống nhau.

Điều này là do% s tham chiếu đến một chuỗi định hướng byte và 'ä' trong UTF-8 cho kết quả là 2 byte.

Theo như tôi có thể kiểm tra, không có shell nào khác hoạt động không chính xác.

Kết quả bạn mong đợi có thể được nhìn thấy với những thứ như:

printf '%2S\n' ä

nhưng điều này không được hỗ trợ bởi bất kỳ shell nào mà tôi đã thử nghiệm.