Як я можу отримати рядки, де певне слово повторюється рівно N разів?


8

Для цього дані:

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

Я хочу цього виходу:

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

Отримання цілих рядків містить лише три повторені слова "це". (нечутливий регістр)


4
Для занадто широкого виборця: як питання може бути більш конкретним?
Яків Влійм

@JacobVlijm У тому, що "занадто багато можливих відповідей". Виберіть $RANDOM_LANGUAGE- хтось зможе придумати рішення в ньому.
muru

@muru Я б сказав, навпаки, обмеження його однією мовою зробить це питанням, орієнтованим на програмування (мову). Тепер це питання, зосереджене на проблемі . Можливо, існує багато можливих рішень (мов), але не так багато очевидних.
Яків Влійм

Відповіді:


13

У perl, замініть thisна себе нечутливий регістр і підрахуйте кількість замін:

$ 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

Замість цього використовуйте кількість матчів :

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

Якщо у вас є GNU awk, дуже простий спосіб:

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

Кількість полів буде на один більше, ніж кількість розділювачів.


Навіщо замінювати? ми не можемо порахувати це безпосередньо без заміни?
αғsnιη

Дійсно , ми можемо розраховувати, код трохи довше: stackoverflow.com/questions/9538542 / ...
Муру

Підтвердження для команди gawk.
Шрі

9

Якщо ваш вихідний файл є tmp.txt,

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

Зліва grep виводить усі рядки, які не мають 4 або більше випадків невідчутливості регістру "цього" в tmp.txt.

Результат передається вправо затискачем, який виводить усі рядки з 3 і більше входженнями в результат лівого грепа.

Оновлення: Завдяки @Muru, ось краща версія цього рішення,

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

замініть 4 на n + 1 і 3 на n.


Це не вдасться для N> 4. І перше grepпотрібно закінчити *.
ps95

1
Я маю на увазі, що ви не можете записати це за N = 50. І питання точно для трьох, тому вам потрібна ще одна греп, яка відкидає всі виходи, що містять менше або дорівнює двом this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
ps95

@ prakharsingh95 Він не пройшов для n> 4 і * не потрібно в першому грепі.
Шрі

1
@KasiyA як ти сприймаєш мою відповідь?
Шрі

5
Спростіть це трохи: grep -Eiv '(.*this){4,}' | grep -Ei '(.*this){3}'- це може зробити його практичним для N = 50.
муру

9

У python це зробить цю роботу:

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

Виходи:

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

Або читати з файлу, з файлом як аргументом:

#!/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)
  • Вставте скрипт у порожній файл, збережіть його як find_3.py, запустіть його командою:

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

Звичайно, слово "це" можна замінити будь-яким іншим словом (або іншим рядком або розділом рядка), а кількість входів у рядку можна встановити на будь-яке інше значення у рядку:

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

Редагувати

Якщо файл буде великим (сотні тисяч / мільйони рядків), код нижче був би швидшим; він читає файл у рядку, а не завантажує файл одразу:

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

Я не фахівець з пітонів, як я можу читати з файлу? подяка
αғsnιη

1
@KasiyA відредаговано, щоб використовувати файл як аргумент.
Яків Влійм

Цікаво: чому ви не використовували генератор у другому фрагменті коду?
муру

6

Ви можете трохи пограти з awkцим:

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

Це повертає:

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

Пояснення

  • Що ми робимо - це визначити роздільник поля для thisсебе. Таким чином, рядок матиме стільки полів +1, скільки разів thisз’являється слово .

  • Щоб зробити випадок нечутливим, ми використовуємо IGNORECASE = 1. Див. Посилання: Чутливість до випадків відповідності .

  • Тоді, просто сказати, NF==4щоб отримати всі ті рядки, що мають thisрівно три рази. Більше не потрібен код, оскільки {print $0}(тобто надрукувати поточний рядок) - це поведінка за замовчуванням, awkколи вираз оцінюється на True.


Вже розміщено , але добре пояснення.
муру

@muru о, я цього не бачив! Мої вибачення та +1 для вас.
fedorqui

5

Припускаючи, що рядки зберігаються у файлі з назвою FILE:

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

1
Дякую, ви можете видалити свою sed ...команду та замість цього додати -oопцію grep -oi ...
αғsnιη

Простіше:$(grep -ic "this" <<<"$line")
muru

2
@muru Ні, -cпараметр буде рахувати кількість рядків, які співпадають зі словами "це", а не числом "цього" у кожному рядку.
αғsnιη

1
@KasiyA Ага, так. Моє ліжко.
муру

@KasiyA, чи не було б -lі -wв цьому випадку рівнозначним?
ps95

4

Якщо ви знаходитесь у Vim:

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

Це буде просто друкувати відповідні рядки.


Хороший приклад пошуку рядків з n входженнями слова при використанні Vim.
Шрі

0

Рубін однолінійний розчин:

$ 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

Працює в досить простий спосіб: ми перенаправляємо файл на стандартний ввід рубіна, рубін отримує рядок зі стандартного вводу, очищає його з chompі downcase, і scan().countдає нам число входжень підрядка.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.