URL encoding/decoding com sed

Existem várias formas de fazer encoding/decoding de urls. Geralmente os programadores já utilizam funções prontas para isso. Mas você realmente sabe o que essas funções estão fazendo? Para este artigo, escolhi o sed como ferramenta para substituir os códigos e aponto as RFCs que discorrem sobre o assunto.

Tempo estimado de leitura: 4 minutos

Introdução

O URL encoding deve ser aplicado toda vez que for necessário utilizar um caractere reservado numa URL. Mas o que são esses caracteres reservados e quem definiu isso?

Os caracteres reservados estão explicitamente descritos na RFC 3986: https://datatracker.ietf.org/doc/html/rfc3986#section-2.2

São eles:

reserved    = gen-delims / sub-delims

gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

sub-delims  = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

Ou seja: “:” , “,” , “?” , “#” , “[” , “]” , “@”, “!” , “$” , “&” , “‘” , “(” , “)”, “*” , “+” , “,” , “;” , “=”

Para fazer o decode, saiba que utilizam-se os códigos hexadecimais da tabela ASCII. Confira a tabela pelo man:

man ascii

As URLs encodadas apresentam o % antes de cada número hexadecimal da tabela ASCII. Portanto, para criar o encoding, basta substituir o caractere reservado por %hexadecimal! =D

Considere que o seu shell vai ler interpretar o hexadecimal com o respectivo código de escape. Para o bash, vamos usar o \x. Veja a tabela acima e faça seus próprios testes. Para a exclamação !, o código é o 21. Veja:

$ echo -e "\x21"
!

Substituindo com sed

Vamos analizar uma função simples com sed para fazer o decode:

    #!/bin/bash
    URL_DECODE="$(echo "$1" | sed -E 's/%([0-9a-fA-F]{2})/\\x\1/g;s/\+/ /g'"
    echo -e "$URL_DECODE"

Basicamente o comando do sed s/%([0-9a-fA-F]{2})/\x\1/g substitui todos os % por \x, desde que os 2 caracteres seguintes representem um número hexadecimal (de 00 a FF). Depois, a opção -e do echo é ativada para interpretar esse hexadecimal. Ah, e o segundo comando do sed s/\+/ /g está substituindo eventuais sinais de + por espaço =). O -E do sed é para habilitar o uso de expressões regulares modernas, para evitar muitos caracteres de escape que sujam a sintaxe.

Para um script um pouco mais sofisticado, que também faça o encoding, daí usamos um monte de comandos sed na sequência.

Veja o código completo, que inclui todos os caracteres reservados da RFC 3986:

    #!/bin/bash
    #
    # Enconding e Decoding de URL com sed
    #
    # Por Daniel Cambría
    # [email protected]
    #
    # jul/2021

    function url_decode() {
    echo "$@" \
        | sed -E 's/%([0-9a-fA-F]{2})/\\x\1/g;s/\+/ /g'
    }

    function url_encode() {
        # Conforme RFC 3986
        echo "$@" \
        | sed \
        -e 's/ /%20/g' \
        -e 's/:/%3A/g' \
        -e 's/,/%2C/g' \
        -e 's/\?/%3F/g' \
        -e 's/#/%23/g' \
        -e 's/\[/%5B/g' \
        -e 's/\]/%5D/g' \
        -e 's/@/%40/g' \
        -e 's/!/%41/g' \
        -e 's/\$/%24/g' \
        -e 's/&/%26/g' \
        -e "s/'/%27/g" \
        -e 's/(/%28/g' \
        -e 's/)/%29/g' \
        -e 's/\*/%2A/g' \
        -e 's/\+/%2B/g' \
        -e 's/,/%2C/g' \
        -e 's/;/%3B/g' \
        -e 's/=/%3D/g'
    }

    echo -e "URL decode: " $(url_decode "$1")
    echo -e "URL encode: " $(url_encode "$1")

Nota sobre encoding de query strings

Muitas vezes o sinal de + irá aparecer em URLs para substituir o espaço. Isso ocorre quando o texto encontra-se numa query string. Veja este seção na RFC1866: https://datatracker.ietf.org/doc/html/rfc1866#section-8.2.1

Mas para qualquer outra codificação HTML, deve-se usar o percent-encoding (URL encoding).

Unicode

Ok, agora que você já entendeu a lógica da coisa, deve estar se perguntando: e se eu usar caracteres acentuados?

Bom, os acentuados não estão na tabela ASCII, mas no padrão Unicode. Esse padrão pode aparecer como UTF-8, UTF-16 e UTF-32 (UTF= Unicode Transformation Format, leia mais em https://www.unicode.org/faq/utf_bom.html). Você pode saber mais sobre Unicode direto da fonte https://unicode.org/.

Se o padrão para usar um número hexadecimal é \x, o unicode é \u. Por exemplo:

echo -e "\u2623"
printf "\u2623"
python -c 'print u"\u2623"'

Para verificar qual é o respectivo código hexadecimal, user o hexdump:

$ echo -en "☣" | hexdump
0000000 e2 98 a3

$ echo -e "\xe2\x98\xa3"
☣

Para conferir o código unicode a partir de um código hexadecimal, esta área do site da Unicode que faz lookup dos code charts dos caracteres deveria ser o suficiente, mas ele só aceita hexadecimal de UTF-16. Mas é possível consultar qual o código unicode de hexadecimal de UTF-8 através do lookup que o site scarfboy realiza. Dê uma conferida:

Unicode no bash do MacOS

No MacOS, por problemas licenciamento de software com o bash a partir da versão 4.0, não conseguimos gerar unicode como ☣ com echo -e "\u2623". Mas você pode instalar o bash 5+ atualizadíssimo usando brew install bash. Se nunca usou o brew, é bem fácil de instalar, consulte o site do autor https://brew.sh. E neste outro artigo, está bem detalhado o procedimento para tornar o novo bash como padrão. Felizmente, usuários de linux não terão esse problema. =D

Se quiser gerar uma lista ENORME de caracteres unicode, experimente esse script abaixo. Lembre-se de salvá-lo num arquivo e dar permissão de executável com chmod +x . Caso não apareça nenhum caractere, releia o parágrafo anterior e atualize seu bash XD

#!/bin/bash
for y in $(seq 0 524287)
  do
  for x in $(seq 0 7)
  do
    a=$(expr $y \* 8 + $x)
    echo -ne "$a \\u$a "
  done
  echo
done

Veja também

Dúvidas? Poste nos comentários.
Até a próxima!

Sobre o autor

Uma resposta

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Mais artigos

bureau-it.com