Как я могу получить строки, где определенное слово повторяется ровно 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 Я бы сказал наоборот, если ограничить его одним языком, то это станет вопросом программирования (языка). Теперь это проблемный вопрос. Возможных решений (языков) может быть много, но не так много очевидных.
— Джейкоб Влейм

Ответы:


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'

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


Зачем заменять? мы не можем посчитать это напрямую без замены?
— αғsнιη

Действительно, мы можем посчитать, код немного длиннее: stackoverflow.com/questions/9538542/…
— muru

Upvote для команды gawk.
— Шри

9

Предполагая, что ваш исходный файл - tmp.txt,

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

Левый grep выводит все строки, которые не имеют 4 или более регистрозависимых вхождений «this» в tmp.txt.

Результат передается в правый grep, который выводит все строки с 3 или более вхождениями в левом результате grep.

Обновление: благодаря @Muru, вот лучшая версия этого решения,

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

замените 4 на n + 1 и 3 на n.


Это потерпит неудачу при N> 4. И первое grepдолжно закончиться *.
— PS95

1
Я имею в виду, что вы не можете написать это для N = 50. И вопрос точно для трех, поэтому вам нужен еще один grep, который отбрасывает все выходные данные, содержащие меньше или равные двум this. grep -iv '.*this.*this.*this.*this.*' tmp.txt | grep -i '.*this.*this.*this.* |grep -iv '.*this.*this.'
— PS95

@ prakharsingh95 Это не удалось при n> 4 и * не требуется в первом grep.
— Шри

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())

Я не эксперт по Python, как я могу читать из файла? спасибо
— αғsнιη

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.


Уже выложено , но хорошее объяснение.
— Муру

@ Муру, о, я этого не видел! Мои извинения и +1 для вас.
— Федорки

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 ...вместо.
— αғsнιη

Проще:$(grep -ic "this" <<<"$line")
— Муру,

2
@muru Нет, -cопция будет подсчитывать количество строк, которые соответствуют «this», а не количеству «this» слов в каждой строке.
— αғsнιη

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

Работает довольно просто: мы перенаправляем файл в stdin ruby, ruby ​​получает строку из stdin, очищает ее с помощью chompи downcaseи scan().countдает нам количество вхождений подстроки.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.