regexp que corresponde a todos os tokens independentemente da ordem

4

Eu tenho uma pergunta rápida (e esperançosamente simples) sobre regexps. Estou tentando pensar em um regexp que corresponda a todos os conjuntos de tokens, independentemente da ordem.

Por exemplo, eu tenho um arquivo com os nomes dos estados dos EUA

Abbreviation:State name:Capital:Became a state
AL:Alabama:Montgomery:December 14, 1819
AK:Alaska:Juneau:January 3, 1959
AZ:Arizona:Phoenix:February 14, 1912
...
WI:Wisconsin:Madison:May 29, 1848
WY:Wyoming:Cheyenne:July 10, 1890

Digamos que eu queira encontrar todos os estados com as letras "A", "R" e "N" em seus nomes (sem distinção entre maiúsculas e minúsculas).

Eu poderia fazer um

$ cut -d: -f2 states.txt | tail -n +2 | grep -i a | grep -i r | grep -i n

que com certeza produz

Arizona
Arkansas
California
Maryland
Nebraska
New Hampshire
North Carolina
North Dakota
Rhode Island
South Carolina
Virginia
West Virginia

Existe alguma maneira de combinar todas as três letras se elas ocorrerem em qualquer ordem usando um único regexp?

    
por TimGJ 04.09.2014 / 12:34

4 respostas

2

Você deve usar awk :

$ awk '/a|A/ && /R|r/ && /N|n/' file
Arizona
Arkansas
California
Maryland
Nebraska
New Hampshire
North Carolina
North Dakota
Rhode Island
South Carolina
Virginia
West Virginia

Com gawk , você pode usar IGNORECASE :

gawk '/a/ && /r/ && /n/' IGNORECASE=1 file
    
por 04.09.2014 / 12:38
2

O comando grep não tem um operador AND adequado, portanto você precisa ser criativo ao tentar resolver problemas como este. Você pode fazer, como você escolheu fazer e encadear vários grep juntos. Mas você também pode fazer algo assim:

$ echo -e "arie\narin" | grep -i '[arn].*[arn].*[arn]'
arin

Isso corresponderá a qualquer sequência que contenha uma combinação de a, r ou n e deverá conter três ocorrências de caracteres desse conjunto.

Palavras com espaços

Para lidar com espaços, você pode adaptar o regex acima da seguinte forma:

$ echo -e "arie\narin\nar nie" | \
    grep -i '[arn][[:alpha:]]*[arn][[:alpha:]]*[arn]'
arin

Aqui, em vez de aceitar qualquer tipo de caractere entre os blocos [arn] , estamos sendo mais seletivos, pegando apenas caracteres do [[:alpha:]] set. Também estamos dizendo grep que queremos * , ou seja, zero ou mais desses caracteres no meio.

    
por 04.09.2014 / 13:49
0
cut -d: -f2 states.txt | tail -n +2 | egrep -i  '[arn].*[arn].*[arn]'
    
por 04.09.2014 / 13:46
0

Bem, uma opção é sed , embora isso possa ser substancialmente mais lento que a alternativa grep

cut -d: -f2 states.txt | tail -n +2 |  sed -n -e '/a/I{/r/I{/n/Ip}}'
Arizona
Arkansas
California
Maryland
Nebraska
New Hampshire
North Carolina
North Dakota
Rhode Island
South Carolina
Virginia
West Virginia
    
por 04.09.2014 / 20:10