Wie kann ich Zeilen erhalten, in denen ein bestimmtes Wort genau N-mal wiederholt wird?

8

Für diese gegebene Eingabe:

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

Ich möchte diese Ausgabe:

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

Das Abrufen ganzer Zeilen enthält nur drei wiederholte "dieses" Wörter. (Groß- und Kleinschreibung wird nicht berücksichtigt)

αғsнιη
quelle
4
An den zu breiten Wähler: Wie kann eine Frage möglicherweise spezifischer werden?
Jacob Vlijm
@JacobVlijm Darin gibt es "zu viele mögliche Antworten". Wählen Sie $RANDOM_LANGUAGE- jemand wird in der Lage sein, eine Lösung darin zu finden.
Muru
@muru Ich würde das Gegenteil sagen, die Beschränkung auf eine Sprache würde es zu einer programmier- (sprach-) zentrierten Frage machen. Jetzt ist es eine problemzentrierte Frage. Es gibt vielleicht viele mögliche Lösungen (Sprachen), aber nicht so viele offensichtliche.
Jacob Vlijm

Antworten:

13

In perlErsetzen thismit sich selbst fall unsensibel und die Anzahl der Ersatz zählen:

$ 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

Verwenden Sie stattdessen eine Anzahl von Übereinstimmungen :

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

Wenn Sie GNU awk haben, ein sehr einfacher Weg:

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

Die Anzahl der Felder ist eins mehr als die Anzahl der Trennzeichen.

muru
quelle
Warum ersetzen? können wir es nicht direkt ohne ersetzen zählen?
αғsнιη
In der Tat können wir zählen, der Code ist etwas länger: stackoverflow.com/questions/9538542/…
muru
Upvote für den Gawk-Befehl.
Sri
9

Angenommen, Ihre Quelldatei ist tmp.txt,

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

Das linke grep gibt alle Zeilen aus, bei denen in tmp.txt nicht 4 oder mehr Vorzeichen ohne Berücksichtigung der Groß- und Kleinschreibung vorhanden sind.

Das Ergebnis wird an den rechten grep weitergeleitet, der alle Zeilen mit 3 oder mehr Vorkommen im linken grep-Ergebnis ausgibt.

Update: Dank @Muru ist hier die bessere Version dieser Lösung:

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

Ersetzen Sie 4 durch n + 1 und 3 durch n.

Sri
quelle
Dies würde für N> 4 fehlschlagen. Und das erste grepmuss mit enden *.
ps95
1
Ich meine, Sie können dies nicht für N = 50 schreiben. Und die Frage ist für genau drei, also brauchen Sie einen anderen grep, der alle Ausgaben verwirft, die weniger als oder gleich zwei enthalten this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
ps95
@ prakharsingh95 Es ist nicht für n> 4 fehlgeschlagen und * ist im ersten grep nicht erforderlich.
Sri
1
@ KasiyA Wie sehen Sie meine Antwort?
Sri
5
Vereinfachen Sie es ein wenig: grep -Eiv '(.*this){4,}' | grep -Ei '(.*this){3}'- Dies könnte es für N = 50 praktisch machen.
Muru
9

In Python würde dies den Job machen:

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

Ausgänge:

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

Oder um aus einer Datei mit der Datei als Argument einzulesen:

#!/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)
  • Fügen Sie das Skript in eine leere Datei ein, speichern Sie es unter find_3.pyund führen Sie es mit dem folgenden Befehl aus:

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

Natürlich kann das Wort "this" durch ein anderes Wort (oder einen anderen String oder Zeilenabschnitt) ersetzt werden, und die Anzahl der Vorkommen pro Zeile kann auf einen anderen Wert in der Zeile gesetzt werden:

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

Bearbeiten

Wenn die Datei groß wäre (Hunderttausende / Millionen Zeilen), wäre der folgende Code schneller. Es liest die Datei pro Zeile, anstatt sie sofort zu laden:

#!/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())
Jacob Vlijm
quelle
Ich bin kein Python-Experte. Wie kann ich aus einer Datei lesen? danke
αғsнιη
1
@KasiyA bearbeitet, um die Datei als Argument zu verwenden.
Jacob Vlijm
Nur neugierig: Warum haben Sie im zweiten Code-Snippet keinen Generator verwendet?
Muru
6

Sie können ein bisschen damit spielen awk:

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

Dies gibt zurück:

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

Erläuterung

  • Wir definieren das Feldtrennzeichen für thissich. Auf diese Weise hat die Zeile so viele Felder +1, wie das Wort thiserscheint.

  • Um die Groß- und Kleinschreibung nicht zu berücksichtigen, verwenden wir IGNORECASE = 1. Siehe Referenz: Groß- / Kleinschreibung beim Matching .

  • Dann ist es nur eine Frage der Aussage NF==4, alle diese Zeilen thisgenau dreimal zu haben. Es wird kein Code mehr benötigt, da {print $0}(dh die aktuelle Zeile drucken) das Standardverhalten ist, awkwenn ein Ausdruck ausgewertet wird True.

fedorqui
quelle
Bereits gepostet , aber gute Erklärung.
Muru
@muru oh, ich habe es nicht gesehen! Ich entschuldige mich und +1 für Sie.
Fedorqui
5

Angenommen, die Zeilen werden in einer Datei mit dem Namen gespeichert FILE:

while read line; do 
    if [ $(grep -oi "this" <<< "$line" | wc -w)  = 3 ]; then 
        echo "$line"; 
    fi  
done  <FILE
ps95
quelle
1
Vielen Dank, Sie können Ihren sed ...Befehl entfernen und stattdessen eine -oOption für hinzufügen grep -oi ....
αғsнιη
Einfacher:$(grep -ic "this" <<<"$line")
Muru
2
@muru Nein, die -cOption zählt die Anzahl der Zeilen , die mit "this" übereinstimmen, nicht die Anzahl der "this" -Wörter in jeder Zeile.
αғsнιη
1
@ KasiyA Ah, ja. Mein Fehler.
Muru
@ KasiyA, wäre -lund -wwäre in diesem Fall nicht gleichwertig?
ps95
4

Wenn Sie in Vim sind:

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

Dadurch werden nur übereinstimmende Zeilen gedruckt.

Bohr
quelle
Schönes Beispiel für die Suche nach Zeilen mit n Wortvorkommen bei Verwendung von Vim.
Sri
0

Ruby Einzeiler-Lösung:

$ 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

Funktioniert ganz einfach: Wir leiten Dateien in Rubys Standard um, Ruby erhält die Zeile von Standard, bereinigt sie mit chompund downcaseund scan().countgibt die Anzahl der Vorkommen eines Teilstrings an.

Sergiy Kolodyazhnyy
quelle