Como apagar todas as ocorrências de uma lista de palavras de um arquivo de texto?

5

Eu tenho um arquivo contendo uma lista de palavras. Desejo remover todas as ocorrências de todas as palavras deste arquivo de um arquivo de texto grande.

Exemplo:

Arquivo 1

queen
king

Exemplo de arquivo de texto

Both the king and queen are monarchs. Will the queen live? Queen, it is!

Isso é o que eu tentei:

sed -i 's/queen/ /g' page.txt
sed -i 's/Queen/ /g' page.txt

Saída

Both the and are monarchs. Will the live? , it is!

A lista de palavras que eu tenho é grande (mais de 50000 palavras). Como posso fazer isso sem ter que especificar o padrão na linha de comando?

    
por user110327 10.11.2016 / 13:21

3 respostas

5

Para seu caso de uso real, eu recomendo a resposta de terdon usando o Perl .

No entanto, a versão simples, sem manipular palavras que são substrings de outras palavras (por exemplo, remover "king" de "hiking"), é para use um comando Sed para gerar o comando executado por uma instância Sed diferente no seu arquivo atual.

Nesse caso, com wordfile contendo "king" e "queen" e textfile contendo seu texto:

sed -e "$(sed 's:.*:s/&//ig:' wordfile)" textfile

Observe que o sinalizador " i case" é uma extensão do GNU, não padrão.

    
por 10.11.2016 / 13:44
3

A maneira simples mas ineficiente é processar o arquivo várias vezes, uma vez para cada palavra de entrada:

$ while read w; do sed -i "s/$w//ig" file2 ; done < file1
$ cat file2
Both the  and  are monarchs. Will the  live? , it is!

Isso pode ser muito lento para arquivos grandes (e também corresponde a substrings). Você poderia fazer isso em uma única passagem com o Perl:

perl -lpe 'BEGIN{open(A,"file1"); chomp(@k = <A>)} 
                 for $w (@k){s/\b\Q$w\E\b//ig}' file2 

O \b certifica-se de que apenas correspondemos aos limites das palavras, \Q\E certifica-se de que $w é considerado literalmente. Isso impedirá que o script corresponda a hiking , mas ainda corresponderá a high-king . Para evitar isso, você precisa listar explicitamente os caracteres que definem uma palavra:

perl -Mopen=locale -Mutf8 -lpe '
  BEGIN{open(A,"file1"); chomp(@k = <A>)} 
  for $w (@k){s/(^|[ ,.—_;-])\Q$w\E([ ,.—_;-]|$)/$1$2/ig}' file2 

Esse de caracteres não-ASCII acima precisa ser inserido na codificação UTF-8, pois estamos informando que perl o código está escrito em UTF-8 com -Mutf8 . Estamos usando -Mopen=locale para o conteúdo dos arquivos e stdout para ser decodificado / codificado no conjunto de caracteres do locale.

    
por 10.11.2016 / 13:44
0

salve este script no arquivo d : ( DOWNLOAD DO GIST GIST )

#!/bin/bash

LIST=${1:?"LIST word"}
FILE=${2:?"FILE name not set"}

L=$( sed -e ':a;N;$!ba;s_\n_\x00_g' ${LIST}|sed -e 's_\x00_ \|_g' -e's_\(\|\)*$__g')
P='s_\('$L'\)__ig'
O="sed -e '$P'  ${FILE}"

eval "${O}"

depois execute:

bash ./d LIST FILE 

se você quiser salvar o arquivo, você pode executar este comando:

bash ./d LIST FILE  | tee NewFILE

OR

bash ./d LIST FILE > NewFile

eu li o LIST WORD e mudei para o formato do regex, por exemplo, eu mudo o seu queen e king e test para este formato:

queen\|king\|test

crie então o comando sed com este parâmetro:

sed -e 's_\(queen\|king\|test\) *__ig' FILE

com este script bash, lemos uma vez LISTWORD e uma vez FILE para substituir

    
por 10.11.2016 / 14:03