shell-script-pt
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script-pt] Comparando strings (com acento / char especial vs


From: Arkanon
Subject: Re: [shell-script-pt] Comparando strings (com acento / char especial vs sem acento / char especial)
Date: Fri, 13 Nov 2020 23:17:34 -0300

Também passei por essa novela da tradução de caracteres um tempo atrás, professor Julio.

Vamos explorar um pouco o problema :)

Ao sugerir o uso do iconv em relação à mapeamentos customizados com tr ou sed, eu estava pensando especificamente na praticidade do suporte ao código a longo prazo, uma vez que o iconv deve matar "automagicamente" todos os casos de transliteração. Ainda mais olhando os exemplos que o George mapeou no sed dele. Tem letra lá que eu nem sabia que existia... :-p

Um exemplo rápido com uma amostra da tabela ASCII:

amostra=$(lynx -dump https://www.ime.usp.br/~glauber/html/acentos.htm | grep '&[^# ]')

echo "$amostra"
#                Á Á È È ô ô  Ç Ç
#                á á è è Ò Ò ç ç
#                ...
#                Ê Ê  ó ó ü ü   þ þ
#                ê ê  Ô Ô             ß ß

iconv -f UTF-8 -t ASCII//TRANSLIT <<< $amostra
#                A &Aacute; E &Egrave; o &ocirc;  C &Ccedil;
#                a &aacute; e &egrave; O &Ograve; c &ccedil;
#                ...
#                E &Ecirc;  o &oacute; u &uuml;   th &thorn;
#                e &ecirc;  O &Ocirc;             ss &szlig;


Mesmo caracteres que não tem o que seria um correspondente "simples" no alfabeto, como o thorn por ex, ele já transcreve com o dígrafo ou de alguma forma adequada.
Talvez seja realmente o caso de se analisar adequadamente o quanto a entrada poderá variar. Se ela ficar restrita a coisas como ã, é, ç, ª, etc, claramente um tr ou sed são simples, eficientes e eficazes. Meu receio é que daqui a um ano comecem a aparecer caracteres alienígenas e não tenha ninguém por perto para "consertar" o script ;)

Por uma questão de legibilidade e manutenção, vamos montar o mapeamento em arrays e depois juntar todos os elementos.

vetor_original=(
  ÁÂÀÄÃÅáâàäãå
  ÉÊÈËéêèë
  ÍÎÌÏíîìï
  ÓÔÒÖÕØóôòöõø
  ÚÛÙÜúûùü
  Çç
  Ññ
  Ðð
  Ýý
)

vetor_resultante=(
  AAAAAAaaaaaa
  EEEEeeee
  IIIIiiii
  OOOOOOoooooo
  UUUUuuuu
  Cc
  Nn
  Dd
  Yy
)


# ®   ©   Þ  þ  ß  Æ  æ
# (R) (C) TH th ss AE ae
O mapeamento dos caracteres dígrafos precisam ser implementados em comandos separados no código sed. Deixando eles de fora agora, se não acelerar o código, também não vai atrasar.
E o tr não efetua esse mapeamento de caractere em string. Menos um ponto pra ele :-p

string_original=${vetor_original[@]}
string_original=${string_original// /}

echo "${vetor_original[@]}"
echo "$string_original"

string_resultante=${vetor_resultante[@]}
string_resultante=${string_resultante// /}




Com sed:

sed y/$string_original/$string_resultante/ <<< $amostra
#                A &Aacute; E &Egrave; o &ocirc;  C &Ccedil;
#                a &aacute; e &egrave; O &Ograve; c &ccedil;
#                ...
#                E &Ecirc;  o &oacute; u &uuml;   þ &thorn;
#                e &ecirc;  O &Ocirc;             ß &szlig;

Mapeou tudo o que mandamos mapear.



Com tr:

tr $string_original $string_resultante <<< $amostra
#                  yA &Aacute; yO &Egrave; yy &ocirc;  yy &Ccedil;
#                  yE &aacute; yo &egrave; yy &Ograve; yy &ccedil;
#                  ...
#                  yi &Ecirc;  yy &oacute; yy &uuml;   y� &thorn;
#                  yo &ecirc;  yy &Ocirc;             y� &szlig;


Problemas no mapeamento pelo tr... :-/



Uma rápida googleada mostra que o tr tem problemas ao manipular strings multi-byte como UTF-8 (atualmente a codificação padrão de caracteres). Há planos de suprir essa necessidade, mas ainda não foram implementados.

file - <<< $amostra
file - <<< $string_original
# /dev/stdin: UTF-8 Unicode text


Considerando nosso objetivo, não faz sentido o que faremos abaixo, mas vamos usar o iconv para converter a $amostra e a $string_original de utf-8 para iso-8859-1 (latin1) só para ver como o tr se comporta a partir daí.

string_original_latin1=$(iconv -f utf-8 -t latin1 <<< $string_original)
        amostra_latin1=$(iconv -f utf-8 -t latin1 <<< $amostra)

file - <<< $string_original_latin1
file - <<< $amostra_latin1
# /dev/stdin: ISO-8859 text

tr $string_original_latin1 $string_resultante <<< $amostra_latin1
#                  A &Aacute; E &Egrave; o &ocirc;  C &Ccedil;
#                  a &aacute; e &egrave; O &Ograve; c &ccedil;
#                  ...
#                  E &Ecirc;  o &oacute; u &uuml;   &thorn;
#                  e &ecirc;  O &Ocirc;             &szlig;


Um pouco melhor.
Os caracteres ainda não traduzidos e, agora codificados como Latin1, a exemplo do thorn (þ), ficaram ilegíveis num terminal utf-8.



Como o Julio Neves sempre nos incentiva a levar a eficiência em consideração, não vamos deixar de comparar as 3 soluções.

Tudo junto, agora:

amostra=$(lynx -dump https://www.ime.usp.br/~glauber/html/acentos.htm | grep '&[^# ]')

vetor_original=(
  ÁÂÀÄÃÅáâàäãå
  ÉÊÈËéêèë
  ÍÎÌÏíîìï
  ÓÔÒÖÕØóôòöõø
  ÚÛÙÜúûùü
  Çç
  Ññ
  Ðð
  Ýý
)

vetor_resultante=(
  AAAAAAaaaaaa
  EEEEeeee
  IIIIiiii
  OOOOOOoooooo
  UUUUuuuu
  Cc
  Nn
  Dd
  Yy
)

string_original=${vetor_original[@]}
string_original=${string_original// /}

string_resultante=${vetor_resultante[@]}
string_resultante=${string_resultante// /}

string_original_latin1=$(iconv -f utf-8 -t latin1 <<< $string_original)
        amostra_latin1=$(iconv -f utf-8 -t latin1 <<< $amostra)

L=4000 # quantas vezes executar cada solução s_i
TIMEFORMAT=%lR

s1() { iconv -f UTF-8 -t ASCII//TRANSLIT <<< $amostra; }
s2() { sed  y/$string_original/$string_resultante/ <<< $amostra; }
s3() { tr $string_original_latin1 $string_resultante <<< $amostra_latin1; }


Podemos averiguar o resultado de cada solução:

s1
s2
s3


E comparamos:

for s in s{1..3}; { echo -n "$s: "; time for ((i=0; i<L; i++)); { $s > /dev/null; }; }
# s1: 0m6,523s
# s2: 0m9,055s
# s3: 0m5,686s


Curiosamente, o sed ficou em terceiro lugar.
O tr ficou em primeiro, mas eu não adotaria ele para ESSE tipo de tradução, considerando sua limitações no trato do UTF-8.
Então, parece que o iconv é realmente uma boa alternativa.

Att,

Em sex., 13 de nov. de 2020 às 09:40, Julio C. Neves <julio.neves@gmail.com> escreveu:
Vamos evitar o (cat|echo|ls) abuse ;-) <<=== Palmas, Aplauso e etc. Sempre digo que a qualidade do script é inversamente proporcional à qtd cat que ele usa.

Uma vez eu medi o tempo para executar o que vcs querem de 3 formas distintas:
iconv, tr e sed 'y/.../.../'

Se não me falha a memória (e está falhando toda hora ;) o mais lento foi o iconv, como me parece que performance faz parte do problema levantado, é bom dar uma olhada (acho que o sed com o cmd y foi o mais veloz).

Abraços,
Julio
» Não tem tempo para fazer um curso presencial?
» Na sua cidade não tem nenhum bom curso de Linux?

Também damos treinamento em sua empresa
em qualquer cidadecom certificado e nota fiscal.








Em qui., 12 de nov. de 2020 às 21:12, Arkanon <arkanon@lsd.org.br> escreveu:
Legal, George.

Mais um sugestão: ou você usa
  gestor=$(echo $gestor | iconv -f UTF-8 -t ASCII//TRANSLIT)
e vai para o inferno, ou usa
  gestor=$(iconv -f UTF-8 -t ASCII//TRANSLIT <<< ${gestor,,})
e vai para o shell :-p.

Vamos evitar o (cat|echo|ls) abuse ;-)

Em qui., 12 de nov. de 2020 às 21:03, George Robinson <george.robinson.br@gmail.com> escreveu:
Verdade Arkanon,

Eu fiz a edição, para ficar correto, porém, ao notar que o sed me criaria um problema futuro, eu modifiquei para usar o iconv e ficou perfeito!!

Muito obrigado por isso!

cat out.txt | while IFS=, read hiringDate name lastName cpf cargo telefone email gestor salario ; do gestor=$(echo $gestor | iconv -f UTF-8 -t ASCII//TRANSLIT <<< ${gestor,,}); bla bla bla ; done

2e927bca-b19b-47f7-8431-1df0222080b7
9d81e9be-7aa8-4782-99a7-ca64d43f7131
c6919f4d-ee40-49d2-8de0-06a676ed448e

Em qui., 12 de nov. de 2020 às 20:57, Arkanon <arkanon@lsd.org.br> escreveu:
George,

O sed e o tr são uma boa se você tem garantia de que não vão cair de paraquedas novos caracteres ao longo do caminho. Mas, se sua amostra de dados (sempre a amostra :-p) não estiver completa, você pode acabar tendo que ficar "dando suporte" ao script ao longo dos anos :-/

A vantagem do iconv é que ele existe para manipular esse tipo de dado e, como há uma boa chance de vir por default ou pelo menos estar a um apt/yum install de distância, você pode apostar que não se incomodará mais com essa parte do algoritmo.

Um coisa que chama atenção no seu sed:

str=MAÇÃ
sed -e 's/[àâã]/a/g; s/[ọõ]/o/g; s/[í,ì]/i/g; s/[ê,ệ]/e/g') <<< ${str,,}

Parece que essa vírgula marcada nas listas está sobrando. Você já não a usou nas duas primeiras listas (do a do o).

Att,

Em qui., 12 de nov. de 2020 às 20:39, George Robinson <george.robinson.br@gmail.com> escreveu:
Boa noite Arkanon,

Eu vi essa solução, e considerei em usar... porém, eu consegui fazer com o sed, usando um "mapa" de caracteres que eu gostaria de usar. Ficou assim:

while IFS=, read hiringDate name lastName cpf cargo telefone email gestor salario ; do gestor=$(echo $gestor | sed -e 's/[àâã]/a/g;s/[ọõ]/o/g;s/[í,ì]/i/g;s/[ê,ệ]/e/g') ; do bla bla bla ; done

Como o único dado que vou comparar é o gestor (todos os outros serão novos dados), eu achei mais simples assim...

Se alguém tiver mais alguma sugestão!

Atenciosamente,

Em qui., 12 de nov. de 2020 às 20:35, Arkanon <arkanon@lsd.org.br> escreveu:
Boa noite, George.

O iconv (no Ubuntu, aparentemente do pacote libc-bin) é uma boa alternativa.

str=Maçã;

Pode fazer o teste de pelo menos duas formas:

iconv -f UTF-8 -t ASCII//TRANSLIT <<< ${str,,} | grep -q maca && echo iguais || echo diff

[[ $(iconv -f UTF-8 -t ASCII//TRANSLIT <<< ${str,,}) == maca ]] && echo iguais || echo diff


Em qui., 12 de nov. de 2020 às 20:24, George Robinson <george.robinson.br@gmail.com> escreveu:
Olá amigos da lista.

Estou buscando uma forma de comparar duas strings onde uma delas é escrita com acento ou caracter especial e a outra não.

Exemplo:

Tornar joão = joão, maçã = maca, ignorando os especiais...

Hoje eu tenho uma string que capturo de uma fonte de dados e preciso comparar com outra fonte de dados para buscar o ID referente, porém, por conta dessa diferença entre um cadastro com ã e outro com a por exemplo, o retorno é vazio. Exemplo abaixo:

out.txt:
2020-12-07,Vinícius,Camargo,36843664806,Analista de Marketing,+55 48 99142-2409,vh.camargo88@gmail.com,Cristina Pose Turnes,5500
2020-11-16,Rodrigo,Marafelli,12487916656,Desenvolvedor,+5535988835248,marafellirodrigo@gmail.com,Eduardo Alessandro Fiorezi,3000
2020-12-01,Guilherme,Rosa,08822812751,Gerente de Remuneração e Benefícios,+5521976748288,guilherme_rosa@me.com,João Guilherme Barbosa de Amorim,16000

Tenho dados de 3 funcionários e quero comparar com um outro sistema que guarda essas infos, para saber se o campo 7 (gestor), existe, a fim de encontrar o ID. Os 3 gestores existem, porém, meu resultado é o seguinte:

2e927bca-b19b-47f7-8431-1df0222080b7
9d81e9be-7aa8-4782-99a7-ca64d43f7131

2 IDs porque de um lado eu tenho João e do outro, tenho Joao, o que me retorna um ID nulo.

Estou capturando os dados através de uma API e gostaria de comparar as strings não importando como foram inseridas. Já consigo por exemplo, ignorar o case, mas não consigo ignorar os especiais.

É possível fazer com o sed, grep, awk, tr ou qualquer outro?

--
George Robinson
Analista de Suporte
Tel: +55 (21) 97449-8138
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
George Robinson
Analista de Suporte
Tel: +55 (21) 97449-8138
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
George Robinson
Analista de Suporte
Tel: +55 (21) 97449-8138
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.
_______________________________________________
Lista brasileira de usuários de shell script
Endereço de e-mail da lista: shell-script-pt@nongnu.org
Para se inscrever ou desinscrever acesse: https://lists.nongnu.org/mailman/listinfo/shell-script-pt
Para ver os arquivos da lista (mensagens anteriores) e pesquisar nelas, acesse https://lists.nongnu.org/archive/html/shell-script-pt/

NOTA: A lista anterior, no Yahoo Groups, foi *desativada*. Por favor utilize somente esta.


--
(o_  @arkanon  (Twitter)     __o
//\   arkanon@lsd.org.br   _`\<,
V_/_      www.lsd.org.br  (_)/(_)
---------------------------------

reply via email to

[Prev in Thread] Current Thread [Next in Thread]