web-dev-qa-db-ja.com

printfを使用して、引数として渡されたUnicode文字をデコードしようとしています

私はこのようにパイプするいくつかのユニコードコードをprintfしようとしています

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

これを手に入れたい

$
%

しかし、これは私が得るものです

printf: missing hexadecimal number in escape

試行錯誤の末、実際には2つの小さな問題があります。1つは理にかなっており、もう1つは完全な謎のようです。


問題1:

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

>$を使用すると、出力で$を確認できます)

何らかの理由で、一部の文字は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

($は出ますが、%はエラーになります)


だから私は私の質問だと思います:

-Iを使用して、引数ごとに1回ではなく、printfを1回実行できるように、printfを数値コードで動作させる方法はありますか?

-printfビルトインが気にしないが、printf exeは気に入らないが、%のみであり、$ではないことの何が問題なのでしょうか。 ?

3
Alex028502

二重展開の問題(\u%sの前に処理される)を回避するには、少なくともBash printf%bを使用できます。

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

入力はさまざまな方法で前処理できます。

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

スタンドアロンprintfGNU coreutils で実装されている)は、Unicode文字仕様に次の制限があります。

printfは、ISO C 99で導入された2つの文字構文を解釈します。4ビットの16進数として指定された16ビットUnicode(ISO/IEC 10646)文字の '\u' hhhh、および32ビットUnicode文字の '\U'、8桁の16進数として指定hhhhhhhhprintfは、LC_CTYPEロケールに従ってUnicode文字を出力します。 U + 0024($)、U + 0040(@)、およびU + 0060( `)を除き、U + 0000…U + 009F、U + D800…U + DFFFの範囲のUnicode文字はこの構文では指定できません。 。

これが、この方法で%を作成できない理由を説明しています。

7
Stephen Kitt

標準のprintfユーティリティは\uxxxxエスケープシーケンスをサポートしていません。以下を参照してください https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

これが機能すると想定すると、いくつかの実装(たとえばksh組み込み)に存在する可能性がある拡張機能に依存しますが、一般的にサポートされるとは期待できません。 printf標準ドキュメントを参照してください。

別の問題は、

printf '\u%s\n' 123

次の呼び出しと同じ結果になります:

printf '\u123\n'

printfはフォーマット文字列を要素ごとに解析し、予期されるフォーマット文字列を認識しないため、これは機能しません。

したがって、bashを使用してスクリプトを実行している場合でも、2つの16進数が続き、エスケープシーケンスが文字列形式で表示される場合は、\uxxバックスラッシュエスケープが展開されることを期待できます。 4桁の16進数を展開したい場合は、フォーマット文字列に文字どおり\Uxxxxを含める必要があります。

2
schily