tentando usar printf para decodificar caracteres Unicode passados ​​como argumentos

tentando usar printf para decodificar caracteres Unicode passados ​​como argumentos

Estou tentando imprimir alguns códigos Unicode que insiro assim

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

esperando conseguir isso

$
%

mas é isso que eu recebo

printf: missing hexadecimal number in escape

Depois de algumas tentativas e erros, na verdade tenho dois problemas menores, e um faz sentido e o outro parece um mistério completo.


Problema 1:

printf '\u%s\n' 0024 0025

me dá isso

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

Problema 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

(usando >for $para que você possa ver $na saída)

Por alguma razão, alguns personagens funcionam com a versão exe, mas outros nem todos funcionam com o printf integrado.


então aqui está uma solução alternativa que funcionaria se não fosse pelo problema nº 2 (mas pode ser um pouco mais lento do que minha ideia original)

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

mas devido ao problema nº 2, meio que funciona:

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

($ sai, mas% recebe erro)


Então acho que minhas perguntas são:

-Existe alguma maneira de fazer printf funcionar com o código numérico para que eu possa executar printf uma vez em vez de uma vez por argumento -I?

-O que estou fazendo de errado que o printfbuilt-in não se importe, mas printfo exe não goste, mas apenas para %e não para $?

Responder1

Para evitar o problema de expansão dupla ( \ué processado antes %s), você pode usar %b, pelo menos no Bash printf:

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

Você pode pré-processar sua entrada de várias maneiras:

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

O autônomo printf,conforme implementado em GNU coreutils, tem as seguintes restrições nas especificações de caracteres Unicode:

printfinterpreta duas sintaxes de caracteres introduzidas na ISO C 99: ' \u' para caracteres Unicode de 16 bits (ISO/IEC 10646), especificados como quatro dígitos hexadecimaisahhe ' \U' para caracteres Unicode de 32 bits, especificados como oito dígitos hexadecimaisahhhhhhh. printfgera os caracteres Unicode de acordo com a LC_CTYPElocalidade. Caracteres Unicode nos intervalos U+0000…U+009F, U+D800…U+DFFF não podem ser especificados por esta sintaxe, exceto U+0024 ($), U+0040 (@) e U+0060 (`) .

Isso explica por que você não pode produzir %dessa maneira.

Responder2

O utilitário padrão printfnão suporta \uxxxxsequências de escape, consulte:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

Assumir que isso poderia funcionar depende de extensões que podem estar presentes em algumas implementações (por exemplo, em um kshbuiltin), mas não se pode esperar que sejam suportadas em geral. Veja o printfdocumento padrão.

Outro problema parece ser a sua suposição de que chamar

printf '\u%s\n' 123

resultaria no mesmo que chamar:

printf '\u123\n'

Isso não funciona, pois printfanalisa a string de formato elemento por elemento e não vê a string de formato esperada.

Portanto, mesmo se você estiver usando bashpara executar o script, você pode esperar que o \uxxescape da barra invertida seja expandido se dois dígitos hexadecimais se seguirem e a sequência de escape aparecer literalmente na string de formato. Se você deseja expandir 4 dígitos hexadecimais, você precisa \Uxxxxliteralmente na string de formato.

informação relacionada