Come posso ottenere linee in cui una parola specifica viene ripetuta esattamente N volte?


8

Per questo dato input:

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

Voglio questo risultato:

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

Ottenere intere righe contiene solo tre parole "questa" ripetute. (corrispondenza senza distinzione tra maiuscole e minuscole)


4
All'elettore troppo vasto: come può una domanda diventare più specifica?
Jacob Vlijm,

@JacobVlijm In quanto ci sono "troppe risposte possibili". Scegli $RANDOM_LANGUAGE: qualcuno sarà in grado di trovare una soluzione.
Muru,

@muru Direi il contrario, limitarlo a una lingua lo renderebbe una domanda centrata sulla programmazione (lingua). Ora si tratta di un problema centrato domanda. Ci sono forse molte soluzioni possibili (lingue), ma non così tante ovvie.
Jacob Vlijm,

Risposte:


13

In perl, sostituisci thiscon se stesso senza distinzione tra maiuscole e minuscole e conta il numero di sostituzioni:

$ 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

Utilizzando invece un conteggio delle partite :

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

Se hai GNU awk, un modo molto semplice:

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

Il numero di campi sarà uno in più rispetto al numero di separatori.


Perché sostituire non possiamo contarlo direttamente senza sostituirlo?
αғsнιη,

In effetti possiamo contare, il codice è leggermente più lungo: stackoverflow.com/questions/9538542/…
muru

Upgrade per il comando gawk.
Sri

9

Supponendo che il tuo file sorgente sia tmp.txt,

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

Il grep di sinistra produce tutte le righe che non hanno 4 o più occorrenze insensibili al maiuscolo / minuscolo di "this" in tmp.txt.

Il risultato viene reindirizzato al grep destro, che genera tutte le righe con 3 o più occorrenze nel risultato grep sinistro.

Aggiornamento: grazie a @Muru, ecco la versione migliore di questa soluzione,

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

sostituire 4 con n + 1 e 3 con n.


Ciò fallirebbe per N> 4. E il primo grepdeve finire *.
ps95,

1
Voglio dire che non puoi scrivere questo per N = 50. E la domanda è esattamente per tre, quindi hai bisogno di un altro grep che scarti tutti gli output che contengano meno o uguale a due this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
ps95,

@ prakharsingh95 Non è fallito per n> 4 e * non è richiesto nel primo grep.
Sri

1
@KasiyA cosa ne pensi della mia risposta?
Sri

5
Semplificalo un po ': grep -Eiv '(.*this){4,}' | grep -Ei '(.*this){3}'- questo potrebbe renderlo pratico per N = 50.
Muru,

9

In Python, questo farebbe il lavoro:

#!/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)

uscite:

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

O per leggere da un file, con il file come argomento:

#!/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)
  • Incolla lo script in un file vuoto, salvalo come find_3.py, eseguilo con il comando:

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

Naturalmente la parola "questo" può essere sostituita da qualsiasi altra parola (o altra sezione di stringa o linea) e il numero di occorrenze per linea può essere impostato su qualsiasi altro valore nella linea:

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

modificare

Se il file fosse grande (centinaia di migliaia / milioni di righe), il codice seguente sarebbe più veloce; legge il file per riga anziché caricarlo contemporaneamente:

#!/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())

Non sono un esperto di Python, come posso leggere dal file? grazie
αғsнιη il

1
@KasiyA modificato per utilizzare il file come argomento.
Jacob Vlijm,

Solo curioso: perché non hai usato un generatore nel secondo frammento di codice?
Muru,

6

Puoi giocare un po 'con awkquesto:

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

Questo ritorna:

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

Spiegazione

  • Quello che facciamo è definire il separatore di campo su thisse stesso. In questo modo, la linea avrà tanti campi +1 quante volte thisappare la parola .

  • Per renderlo insensibile alle maiuscole, usiamo IGNORECASE = 1. Vedi riferimento: Sensibilità al maiuscolo / minuscolo in corrispondenza .

  • Quindi, si tratta solo di dire NF==4che tutte quelle linee hanno thisesattamente tre volte. Non è necessario altro codice, poiché {print $0}(ovvero stampa la riga corrente) è il comportamento predefinito di awkquando un'espressione valuta True.


Già pubblicato , ma buona spiegazione.
Muru,

@muru oh, non l'ho visto! Le mie scuse e +1 per te.
fedorqui,

5

Supponendo che le righe siano memorizzate in un file denominato FILE:

while read line; do 
    if [ $(grep -oi "this" <<< "$line" | wc -w)  = 3 ]; then 
        echo "$line"; 
    fi  
done  <FILE

1
Grazie, puoi rimuovere il tuo sed ...comando e aggiungere invece l' -oopzione per grep -oi ....
αғsнιη,

Più semplice:$(grep -ic "this" <<<"$line")
Muru

2
@muru No, l' -copzione conterà il numero di righe corrispondenti a "questo" e non il numero di parole "this" in ciascuna riga.
αғsнιη,

1
@KasiyA Ah, sì. Colpa mia.
Muru,

@KasiyA, non sarebbe -le -wsarà equivalente in questo caso?
ps95,

4

Se sei in Vim:

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

Questo stamperà solo le linee abbinate.


Bell'esempio per cercare linee con n occorrenze di parole, quando si usa Vim.
Sri

0

Soluzione Ruby one-liner:

$ 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

Funziona in modo abbastanza semplice: reindirizziamo il file nello stdin di ruby, ruby ​​ottiene la linea dallo stdin, lo pulisce con chompe downcasee scan().countci dà il numero di occorrenze di una sottostringa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.