Bagaimana saya bisa mendapatkan baris di mana kata tertentu diulang tepat N kali?

8

Untuk input yang diberikan ini:

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

Saya ingin hasil ini:

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

Mendapatkan seluruh baris hanya mengandung tiga kata "ini" yang diulang. (kecocokan huruf besar-kecil)

αғsнιη
sumber
4
Bagi pemilih yang terlalu luas: bagaimana mungkin suatu pertanyaan bisa lebih spesifik?
Jacob Vlijm
@JacobVlijm Dalam bahwa ada "kemungkinan jawaban terlalu banyak". Pilih $RANDOM_LANGUAGE- seseorang akan dapat menemukan solusi di dalamnya.
muru
@uru saya akan mengatakan yang sebaliknya, membatasi ke satu bahasa akan membuatnya menjadi pemrograman (bahasa) pertanyaan terpusat. Sekarang ini adalah pertanyaan yang berpusat pada masalah . Mungkin ada banyak solusi yang mungkin (bahasa), tetapi tidak begitu banyak yang jelas.
Jacob Vlijm

Jawaban:

13

Dalam perl, ganti thisdengan dirinya sendiri case-insensitive dan hitung jumlah penggantian:

$ 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

Alih-alih menggunakan hitungan kecocokan :

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

Jika Anda memiliki GNU awk, cara yang sangat sederhana:

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

Jumlah bidang akan lebih dari jumlah pemisah.

muru
sumber
Mengapa ganti? kita tidak bisa menghitungnya langsung tanpa ganti?
αғsнιη
Memang kita bisa menghitung, kodenya sedikit lebih panjang: stackoverflow.com/questions/9538542/…
muru
Suara positif untuk perintah gawk.
Sri
9

Dengan asumsi file sumber Anda adalah tmp.txt,

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

Grep kiri menampilkan semua baris yang tidak memiliki 4 atau lebih kejadian case-insensitive dari "this" di tmp.txt.

Hasilnya disalurkan ke grep kanan, yang menampilkan semua baris dengan 3 kejadian atau lebih di hasil grep kiri.

Pembaruan: Berkat @Muru, ini adalah versi yang lebih baik dari solusi ini

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

ganti 4 dengan n + 1 dan 3 dengan n.

Sri
sumber
Ini akan gagal untuk N> 4. Dan yang pertama grepharus diakhiri *.
ps95
1
Maksud saya Anda tidak dapat menulis ini untuk N = 50. Dan pertanyaannya adalah tepat tiga sehingga Anda perlu grep lain yang membuang semua output yang mengandung kurang dari atau sama dengan dua this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
ps95
@ prakharsingh95 Tidak gagal untuk n> 4 dan * tidak diperlukan di grep pertama.
Sri
1
@ KasiyA, apa pendapat Anda tentang jawaban saya?
Sri
5
Sederhanakan sedikit: grep -Eiv '(.*this){4,}' | grep -Ei '(.*this){3}'- ini mungkin membuatnya praktis untuk N = 50.
muru
9

Dalam python, ini akan melakukan pekerjaan:

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

output:

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

Atau untuk membaca dari file, dengan file sebagai argumen:

#!/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)
  • Rekatkan skrip ke file kosong, simpan sebagai find_3.py, jalankan dengan perintah:

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

Tentu saja kata "ini" dapat diganti dengan kata lain (atau bagian string atau baris lainnya), dan jumlah kemunculan per baris dapat diatur ke nilai lain apa pun di baris:

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

Edit

Jika file berukuran besar (ratusan ribu / jutaan baris), kode di bawah ini akan lebih cepat; itu membaca file per baris alih-alih memuat file sekaligus:

#!/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())
Yakub Vlijm
sumber
Saya bukan ahli python, bagaimana saya bisa membaca dari file? terima kasih
αғsнιη
1
@KasiyA diedit untuk menggunakan file sebagai argumen.
Jacob Vlijm
Hanya ingin tahu: Mengapa Anda tidak menggunakan generator di cuplikan kode kedua?
muru
6

Anda dapat bermain sedikit dengan awkini:

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

Ini mengembalikan:

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

Penjelasan

  • Apa yang kita lakukan adalah mendefinisikan pemisah bidang thisitu sendiri. Dengan cara ini, baris tersebut akan memiliki banyak bidang +1 sebanyak kali kata tersebut thismuncul.

  • Untuk membuatnya tidak sensitif, kami menggunakan IGNORECASE = 1. Lihat referensi: Sensitivitas Huruf dalam Pencocokan .

  • Kemudian, itu hanya masalah mengatakan NF==4untuk mendapatkan semua kalimat itu thistepat tiga kali. Tidak diperlukan lagi kode, karena {print $0}(yaitu, cetak baris saat ini) adalah perilaku default awkketika ekspresi dinilai True.

fedorqui
sumber
Sudah diposting , tapi penjelasannya bagus.
muru
@uru oh, saya tidak melihatnya! Saya minta maaf dan memberi +1 untuk Anda.
fedorqui
5

Dengan asumsi garis disimpan dalam file bernama FILE:

while read line; do 
    if [ $(grep -oi "this" <<< "$line" | wc -w)  = 3 ]; then 
        echo "$line"; 
    fi  
done  <FILE
ps95
sumber
1
Terima kasih, Anda dapat menghapus sed ...perintah dan menambahkan -oopsi untuk grep -oi ...gantinya.
αғsнιη
Simpler:$(grep -ic "this" <<<"$line")
muru
2
@muru Tidak, -copsi akan menghitung jumlah baris yang cocok dengan kata-kata "ini" bukan jumlah "ini" di setiap baris.
αғsнιη
1
@ Kakya Ah, ya. Salahku.
muru
@KasiyA, bukankah -ldan -wakan setara dalam kasus ini?
ps95
4

Jika Anda berada di Vim:

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

Ini hanya akan mencetak garis yang cocok.

Bohr
sumber
Contoh yang bagus untuk mencari baris dengan n kemunculan kata, saat menggunakan Vim.
Sri
0

Solusi Ruby satu-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

Bekerja dengan cara yang cukup sederhana: kami mengarahkan file ke stdin ruby, ruby ​​mendapat garis dari stdin, membersihkannya dengan chompdan downcase, dan scan().countmemberi kami jumlah kemunculan substring.

Sergiy Kolodyazhnyy
sumber