การเพิ่มสตริง Unicode ด้วย bash's printf

Sep 13 2020

ฉันลองขยายสตริง Unicode ด้วย printf ของ bash และเห็นว่าในขณะนั้น

printf "%2s" a

ให้ผล "a" ที่คาดหวัง

ตัวแปร Unicode

printf "%2s" ä  

ให้ผลตอบแทน "ä" ที่ไม่มีการกดอย่างน่าประหลาดใจ (zsh ให้ผลลัพธ์ที่คาดหวัง)

สาเหตุนี้คืออะไร และฉันจะวางสตริง Unicode ใน bash ได้อย่างไร?

คำตอบ

crackpot Sep 13 2020 at 00:02

ฉันจะวางสตริง Unicode ใน bash ได้อย่างไร

นั่นเป็นวิธีที่เกินความสามารถของ bash หากคุณกำลัง จำกัด "สตริง Unicode" ไว้ที่ ascii ++ (ไม่มีอักขระแบบ double width ไม่มี bidi ไม่มีเครื่องหมายไม่เว้นวรรค ฯลฯ ) คุณอาจตัดสินว่า:

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

อักขระäถูกเข้ารหัสด้วย 2 ไบต์ใน UTF-8 ดังนั้น Printf จึงใช้สำหรับ 2-padded

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

แต่สิ่งนี้ไม่ได้รับการสนับสนุนจากกระสุนใด ๆ ที่ฉันทดสอบ