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.