嘗試使用 printf 解碼作為參數傳入的 unicode 字符

嘗試使用 printf 解碼作為參數傳入的 unicode 字符

我正在嘗試 printf 一些我透過管道輸入的 unicode 程式碼

echo 0024 0025 | xargs -n1 echo # one code per line
  | xargs printf '\u%s\n'

希望得到這個

$
%

但這就是我得到的

printf: missing hexadecimal number in escape

經過一番嘗試和錯誤,我實際上有兩個較小的問題,一種是有道理的,另一種似乎完全是個謎。


問題一:

printf '\u%s\n' 0024 0025

給我這個

-bash: printf: missing unicode digit for \u
\u0024
-bash: printf: missing unicode digit for \u
\u0025

問題2:

> # use built-in for $
> printf '\u0024\n'
$
> # use exe for $
> which printf
/usr/bin/printf
> /usr/bin/printf '\u0024\n'
$
> # now use built-in for %
> printf '\u0025\n'
%
> # but look what happens when we use exe for % !!!!
> /usr/bin/printf '\u0025\n'
/usr/bin/printf: invalid universal character name \u0025

(使用>for以便您可以在輸出中$看到)$

由於某些原因,有些字元可以使用 exe 版本,但有些字元則不能,儘管所有字元都可以使用內建 printf。


所以這裡有一個解決方法,如果不是問題#2,它會起作用(但可能比我最初的想法慢很多)

echo 0024 0025 | xargs -n1 echo # one item per line
  | xargs -I {} printf '\u{}\n'

但由於問題#2,它只起了一半作用:

$ echo 0024 0025 | xargs -n1 echo | xargs -I {} printf '\u{}\n'
$
printf: invalid universal character name \u0025

($ 出來但 % 出現錯誤)


所以我想我的問題是:

- 有沒有辦法讓 printf 使用數字代碼,以便我可以運行 printf 一次,而不是每個參數運行一次-I

-我做錯了什麼printf內建不介意,但printfexe不喜歡,但只為%而不是為$

答案1

為了避免雙重展開問題(\u之前已處理過%s),您可以使用%b,至少在 Bash 中printf

printf '%b\n' \\u0024 \\u0025

您可以透過多種方式預處理輸入:

set 0024 0025
printf '%b\n' "${@/#/\\u}"

獨立式printf,在 GNU coreutils 中實現,對 Unicode 字元規範有以下限制:

printf解釋 ISO C 99 中引入的兩種字元語法: ' \u' 表示 16 位元 Unicode (ISO/IEC 10646) 字符,指定為四個十六進位數字呵呵, 和 ' \U' 表示 32 位元 Unicode 字符,指定為八個十六進位數字哈哈哈哈printf根據LC_CTYPE區域設定輸出 Unicode 字元。此語法無法指定 U+0000…U+009F、U+D800…U+DFFF 範圍內的 Unicode 字符,U+0024 ($)、U+0040 (@) 和 U+0060 (`) 除外。

這解釋了為什麼你不能%以這種方式生產。

答案2

標準printf實用程式不支援\uxxxx轉義序列,請參閱:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

假設這可以工作取決於可能存在於一些實作中(例如內建ksh)的擴展,但不能期望得到普遍支援。請參閱printf標準文件。

另一個問題似乎是你假設調用

printf '\u%s\n' 123

會產生與呼叫相同的結果:

printf '\u123\n'

這不起作用,因為printf逐個元素解析格式字串,但看不到預期的格式字串。

因此,即使您正在用來bash執行腳本,\uxx如果後面跟著兩個十六進制數字並且轉義序列按字面意思出現在格式字串中,您也可能會期望反斜線轉義被擴展。如果您想擴展 4 個十六進位數字,則需要\Uxxxx在格式字串中按字面意思進行。

相關內容