Correspondência de Padrões Excluir Caracteres Duplicados

7

Existe uma expressão regular para o seguinte que combina caracteres em um conjunto de caracteres, mas apenas uma vez? Em outras palavras, uma vez que um personagem é encontrado, remova-o do conjunto.

Se o grep não puder fazer isso, existe um utilitário embutido que pode?

Exemplo:

Characters to match only once:   spine

Entrada:

spine
spines
spin
pine
seep 
spins

Saída:

spine
spin
pine

EDITAR:
Há muitas maneiras de obter essa saída (um exemplo abaixo), mas estou procurando uma maneira de fazer isso sem precisar personalizar o comando para cada padrão que desejo corresponder.

grep '[spine]' input_file | grep -v 's.*s' | ... | grep -v 'e.*e'

    
por Steven 21.07.2011 / 23:41

2 respostas

4

Com expressões regulares no sentido matemático, é possível, mas o tamanho das expressões regulares cresce exponencialmente em relação ao tamanho do alfabeto, por isso não é prático.

Há uma maneira simples com negação e referências anteriores .

grep '[spine]' | grep -Ev '([spine]).*'

O primeiro grep seleciona linhas que contenham pelo menos um einps ; o segundo grep rejeita as linhas que contêm mais de uma (por exemplo, permitindo spinal tap e spend , mas não foobar ou see ).

    
por 22.07.2011 / 12:38
1

Inspirado em sua expressão, posso encontrar uma mais curta, usando egrep:

egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE

que é equivalente a

sed /s.*s/d;/p.*p/d;/i.*i/d;/n.*n/d;/e.*e/d; FILE

E isso é como produzir automaticamente o comando sed a partir da entrada:

#!/bin/bash
word=$1
file=$2
expr=$(for c in $(echo $word | sed 's/./& /g'); do echo -n "/"$c".*"$c"/d;"; done);
sed $expr $file 

Eu tentei uma abordagem parecida com o grep, mas não consegui convencer o shell a usar o padrão grep de uma variável, mas se eu fizesse o eco e inserisse o resultado com o comando cut and paste, o comando funcionava:

expr="'("$(for c in $(echo $wort | sed 's/./& /g'); do echo -n $c".*"$c"|"; done)

egrep -v ${expr/%|/)\'} FILE
# doesn't work, filters nothing, whole file is printed
# check:    
echo egrep -v $(echo $exp) FILE 
egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE
# manually: 
egrep -v '(s.*s|p.*p|i.*i|n.*n|e.*e)' FILE
spine
spin
pine

Talvez eu tenha cometido um erro, talvez eu tenha cometido um erro com a expansão das variáveis.

    
por 22.07.2011 / 00:31