Regex & Sed / Perl: corresponde à palavra que NÃO é precedida por outra palavra

11

Gostaria de usar sed ou perl para substituir todas as ocorrências de uma palavra que não tenha uma determinada palavra na frente dela.

Por exemplo, eu tenho um arquivo de texto que contém um enredo de um filme e quero substituir todas as ocorrências do sobrenome de um personagem pelo primeiro nome, mas somente se o primeiro nome não vier imediatamente antes do sobrenome. .

O texto de exemplo pode ter esta aparência:

John Smith and Jane Johnson talk about Smith's car.

Eu quero que seja assim:

John Smith and Jane Johnson talk about John's car.

Se eu fizer apenas sed 's/Smith/John/' file , eu teria:

John John and Jane Johnson talk about John's car.

O primeiro nome que vem antes do sobrenome será sempre o mesmo. Eu não tenho que lidar com John Smith e Frank Smith . Só preciso de uma maneira de corresponder a Smith que não tem John anterior a ela.

    
por jonescb 06.11.2011 / 03:56

3 respostas

8

Seria fácil com qualquer idioma em que as expressões regulares fossem capazes de olhar para trás. Claro, Perl é o primeiro da lista:

perl -pe 's/(?<!John\W)Smith/John/g' <<< "John Smith and Jane Johnson talk about Smith's car."

O ponto fraco é ter mais de um caractere sem palavra entre "John" e "Smith". Infelizmente, um quantificador como + para \W aumentaria o erro "Erro de comprimento variável não implementado".

    
por 06.11.2011 / 13:33
6

EDITAR .. re seu comentário .. Aqui está um novo script que não se preocupa com (por exemplo) William Smith. Ele temporariamente ofusca os padrões que mantém como Smith (inalterado).

sed -r 's/\<(John) (Smith)\>/\x01x/g; 
        s/\<Smith\>/John/g;  s/\x01x/ /g'

Se você está preocupado com Mr. Sr. Sra ... então isso funciona.

sed -r 's/\<(John|((M(r|rs|s))\.?)) (Smith)\>/\x01x/g
        s/\<Smith\>/John/g; s/\x01x/ /g'

Você pode atender William adicionando o nome dele à lista ou , por exemplo,.% sed -r 's/\<(William|John|...

Este é o script original

sed -r 's/(^|[[:punct:]] |\<[a-z]+ )(Smith\>)/John/'
    
por 06.11.2011 / 07:00
1
 sed -r 's/([^John] )Smith/John/g;s/([^Jane] )Johnson/Jane/g'

O () irá capturar o non-Firstname antes de um LastName, então eles são backref'd no substituto.

Editar

@ manatwork, gilles

Você está certo. Como sobre

sed -r 's/(John Smith)/temp1/g;s/Smith/John/g;s/temp1/John Smith/g'

Isso parece fazer o truque.

    
por 06.11.2011 / 14:56