Verifique se há permutação usando o awk

2

Meu problema é determinar via script de shell se certas strings são permutações umas das outras, por exemplo.

1.Nf3 c5 2.e4 Nc6
1.e4 c5 2.Nf3 Nc6

Como você pode ver, a permutação é baseada em substrings atômicas. Então, em outras palavras, quero saber se as duas strings contendo as mesmas substrings sem considerar a ordem.

O AWK é uma linguagem de programação projetada para processamento de texto avançado. Então, uma ideia que surge é dividir as duas strings em arrays:

{1., Nf3, c5, 2., e4, Nc6}
{1., e4, c5, 2., Nf3, Nc6}

e compare se ambos consistirem em mesmos elementos. Mas não tenho certeza se isso se encaixa muito bem.

Uma segunda abordagem é dividir a primeira string em padrões {1., Nf3, c5, 2., e4, Nc6} e pesquisar na segunda string todos os padrões e criar uma nova string com base nessas correspondências. Afinal, eu pude verificar se a nova string é igual à primeira string. Existem outras abordagens no awk para este processamento de texto específico?

    
por Hölderlin 20.03.2017 / 00:14

3 respostas

3

Eu não acho que awk seja o caminho certo. Basta dividir as strings, classificar os elementos da string e comparar o resultado.

Exemplo com bash :

$ split_and_sort() { sed -r 's/\</\n/g' | sort; }

$ split_sort_and_compare() {
    if [ "$(split_and_sort <<< "$1")" = "$(split_and_sort <<< "$2")" ]
    then echo "Match"
    else echo "No match"
    fi
}

$ split_sort_and_compare "1.Nf3 c5 2.e4 Nc6" "1.e4 c5 2.Nf3 Nc6"
Match

$ split_sort_and_compare "1.Nf3 c5 2.e4 Nc6" "1.e4 c5 2.Nf3 Nc5"
No match

Este é apenas um exemplo grosseiro para ilustrar minha ideia, com minha própria interpretação de como as strings precisam ser divididas e comparadas. Faça suas próprias funções mais elaboradas de acordo com suas regras.

    
por 20.03.2017 / 03:08
1

Apenas para registro, esta é uma solução awk (não muito complicada, no caso), caso você precise integrar esta solução a qualquer um dos seus projetos awk existentes.

a="1.Nf3 c5 2.e4 Nc6"
b="1.e4 c5 2.Nf3 Nc6"
awk 'BEGIN{FS=""}{last=NF;for (i=1;i<=NF;i++) {if (NR==FNR) {a[i]=$i} else {b[i]=$i}}} \
{asort(a);asort(b)}END{{for (k=1;k<=last;k++) if (a[k]!=b[k]) nomatch++}{print (nomatch==0)?"match":"no match"}}' <(echo "$a") <(echo "$b")

Se você quer apenas comparar essas duas strings, eu usaria alguma forma bash, como a resposta de xhienne aconselha ou até algo assim:

[[ $(sort <(grep -o . <<<"$a") |base64) == $(sort <(grep -o . <<<"$b") |base64) ]] && echo "match" || echo "differ"

Em ambos os casos, a lógica é a mesma. A string de entrada é dividida por caractere, depois é classificada uma a uma e as duas cadeias de caracteres classificadas são comparadas.

No modo bash acima, pensei em codificar as strings classificadas para base64 e comparar seus valores base64.

    
por 21.03.2017 / 17:36
1

Uma maneira alternativa de verificar se ambas as strings contêm os mesmos caracteres poderia ser calcular a soma de seus valores ASCII.

$ while read -rn1 char;do sumA+=$(printf '%d+' "'$char'");done <<<"1.Nf3 c5 2.e4 Nc6"
$ while read -rn1 char;do sumB+=$(printf '%d+' "'$char'");done <<<"1.e4 c5 2.Nf3 Nc6"

$ echo "$sumA"
49+46+78+102+51+39+99+53+39+50+46+101+52+39+78+99+54+39+
$ echo "$sumB"
49+46+101+52+39+99+53+39+50+46+78+102+51+39+78+99+54+39+

$ bc <<<"${sumB:0:-1}"
1114
$ bc <<<"${sumA:0:-1}"
1114

Mesma soma numérica = mesmas sequências. Assim, ao comparar esses dois valores bc, você pode ter uma condição de correspondência / não correspondência.

Se um caractere for diferente entre os valores dos strings ascii, a soma será diferente:

$ while read -rn1 char;do sumC+=$(printf '%d+' "'$char'");done <<<"1.Nf3 q5 2.e4 Nc6" #q5 is different than string A
$ echo "$sumC"
49+46+78+102+51+39+113+53+39+50+46+101+52+39+78+99+54+39+
$ bc <<<"${sumC:0:-1}"
1128
    
por 22.03.2017 / 01:36