Como posso obter linhas em que uma palavra específica é repetida exatamente N vezes?

8

Para esta entrada:

How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this

Eu quero essa saída:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Obter linhas inteiras contém apenas três palavras "this" repetidas. (correspondência insensível a maiúsculas)

    
por devWeek 04.01.2015 / 18:13

7 respostas

13

Em perl , substitua this com si mesmo sem distinção entre maiúsculas e minúsculas e conte o número de substituições:

$ perl -ne 's/(this)/$1/ig == 3 && print' <<EOF
How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this
EOF
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Usando uma contagem de correspondências em vez disso:

perl -ne 'my $c = () = /this/ig; $c == 3 && print'

Se você tem o GNU awk, uma maneira muito simples:

gawk -F'this' -v IGNORECASE=1 'NF == 4'

O número de campos será um a mais que o número de separadores.

    
por muru 04.01.2015 / 19:13
9

Assumindo que seu arquivo de origem é tmp.txt,

grep -iv '.*this.*this.*this.*this' tmp.txt | grep -i '.*this.*this.*this.*'

O grep da esquerda mostra todas as linhas que não possuem 4 ou mais ocorrências sem distinção entre maiúsculas e minúsculas de "this" em tmp.txt.

O resultado é canalizado para o grep correto, que produz todas as linhas com 3 ou mais ocorrências no resultado do grep à esquerda.

Atualização: graças ao @Muru, aqui está a melhor versão desta solução,

grep -Eiv '(.*this){4,}' tmp.txt | grep -Ei '(.*this){3}'

substitua 4 por n + 1 e 3 por n.

    
por Sri 04.01.2015 / 19:54
9

Em python, isso faria o trabalho:

#!/usr/bin/env python3

s = """How to get This line that this word repeated 3 times in THIS line?
But not this line which is THIS word repeated 2 times.
And I will get This line with this here and This one
A test line with four this and This another THIS and last this"""

for line in s.splitlines():
    if line.lower().count("this") == 3:
        print(line)

saídas:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Ou para ler de um arquivo, com o arquivo como argumento:

#!/usr/bin/env python3
import sys

file = sys.argv[1]

with open(file) as src:
    lines = [line.strip() for line in src.readlines()]

for line in lines:
    if line.lower().count("this") == 3:
        print(line)
  • Cole o script em um arquivo vazio, salve-o como find_3.py , execute-o pelo comando:

    python3 /path/to/find_3.py <file_withlines>
    

É claro que a palavra "this" pode ser substituída por qualquer outra palavra (ou outra string ou seção de linha), e o número de ocorrências por linha pode ser definido para qualquer outro valor na linha:

    if line.lower().count("this") == 3:

Editar

Se o arquivo fosse grande (centenas de milhares / milhões de linhas), o código abaixo seria mais rápido; ele lê o arquivo por linha em vez de carregar o arquivo de uma só vez:

#!/usr/bin/env python3
import sys
file = sys.argv[1]

with open(file) as src:
    for line in src:
        if line.lower().count("this") == 3:
            print(line.strip())
    
por Jacob Vlijm 04.01.2015 / 18:53
6

Você pode jogar um pouco com awk para isso:

awk -F"this" 'BEGIN{IGNORECASE=1} NF==4' file

Isso retorna:

How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Explicação

  • O que fazemos é definir o separador de campos como this . Desta forma, a linha terá tantos campos +1 quanto vezes a palavra this aparece.

  • Para torná-lo insensível a maiúsculas, usamos IGNORECASE = 1 . Consulte a referência: Diferenciação de maiúsculas e minúsculas na correspondência .

  • Então, é apenas uma questão de dizer NF==4 para obter todas essas linhas tendo this exatamente três vezes. Não é necessário mais código, pois {print $0} (ou seja, imprimir a linha atual) é o comportamento padrão de awk quando uma expressão é avaliada como True .

por fedorqui 05.01.2015 / 15:15
5

Supondo que as linhas estejam armazenadas em um arquivo chamado FILE :

while read line; do 
    if [ $(grep -oi "this" <<< "$line" | wc -w)  = 3 ]; then 
        echo "$line"; 
    fi  
done  <FILE
    
por ps95 04.01.2015 / 19:03
4

Se você estiver no Vim:

g/./if len(split(getline('.'), 'this\c', 1)) == 4 | print | endif

Isso apenas imprimirá linhas combinadas.

    
por Bohr 05.01.2015 / 06:44
0

Solução de uma linha de rubi:

$ ruby -ne 'print $_ if $_.chomp.downcase.scan(/this/).count == 3' < input.txt                                    
How to get This line that this word repeated 3 times in THIS line?
And I will get This line with this here and This one

Funciona de maneira bastante simples: nós redirecionamos o arquivo para o stdin do ruby, o ruby obtém a linha do stdin, limpa com chomp e downcase e scan().count nos dá o número de ocorrências de uma substring.

    
por Sergiy Kolodyazhnyy 07.01.2017 / 11:37