Удвойте каждое третье вхождение строки - PullRequest
3 голосов
/ 10 декабря 2011

У меня есть такой файл:

Sed eleifend orci eget odio
consequat. Sed sagittis ipsum
eget pulvinar. Sed ut lacus
Sed luctus sollicitudin ligula
varius neque. Sed tincidunt
Sed mauris egestas eget. Sed
Curae; Sed aliquam enim Sed,
Sed dictum quis sem. Sed
volutpat tincidunt. Sed lacus.

Я хочу преобразовать его в:

Sed eleifend orci eget odio
consequat. Sed sagittis ipsum
eget pulvinar. Sed Sed ut lacus
Sed luctus sollicitudin ligula
varius neque. Sed tincidunt
Sed Sed mauris egestas eget. Sed
Curae; Sed aliquam enim Sed Sed,
Sed dictum quis sem. Sed
volutpat tincidunt. Sed Sed lacus.

Ответы [ 6 ]

6 голосов
/ 10 декабря 2011

Однострочник Perl может достичь этого с помощью модификатора /e, который допускает логическую подстановку:

$ perl -pi.bak -e 'BEGIN{ $str = "Sed"; } s/(?<=$str)/ ++$cnt % 3 ? "" : " $str" /ge' file.txt

Объяснение

  • -pi.bak

    Построчное редактирование файла на месте.Резервная копия хранится в file.txt.bak

  • BEGIN block

    Укажите значение $str, выполняетсятолько один раз

  • s/PATTERN/REPLACEMENT/ge

    Подстановка регулярных выражений во всех совпадениях в $_, построчно. ЗАМЕНА оценивается как Perl-код.

  • (?<=$str)

    Утверждение с фиксированной длиной

  • ++$cnt % 3 ? "" : " $str"

    Каждый третий матч, добавляйте " $str", иначе ничего не добавляйте

3 голосов
/ 10 декабря 2011

Вы также можете сделать это с помощью awk.

awk -v s=Sed '{for(i=1;i<=NF;i++) {if($i ~ s)cnt++; if(cnt==3) {cnt=0; printf("%s ", s)} printf("%s ", $i)} printf("\n")}' file.txt

ВЫХОД

Sed eleifend orci eget odio 
consequat. Sed sagittis ipsum 
eget pulvinar. Sed Sed ut lacus 
Sed luctus sollicitudin ligula 
varius neque. Sed tincidunt 
Sed Sed mauris egestas eget. Sed 
Curae; Sed aliquam enim Sed Sed, 
Sed dictum quis sem. Sed 
volutpat tincidunt. Sed Sed lacus.
0 голосов
/ 12 декабря 2011

Это может работать для вас:

sed ':a;$!{N;ba};s/\<Sed\>/\x00/g;s/\(\x00\)[^\x00]*\1[^\x00]*\1/& \1/g;s/\x00/Sed/g' file

Пояснение:

  1. Подать файл в пространство шаблона.
  2. В конце файла глобально замените выбранную строку маловероятным символом.
  3. Глобально замените каждую строку, в которой неправдоподобный символ встречается три раза, самостоятельно, добавляя маловероятный символ.
  4. Глобально заменить маловероятный символ выбранной строкой.
0 голосов
/ 10 декабря 2011
s/(\bSed\b.*?\bSed\b.*?\bSed\b)/$1 Sed/gsm
0 голосов
/ 10 декабря 2011

Этот скрипт примет аргумент в качестве слова для умножения.Снятие знаков препинания сделает счет точным и позволит избежать повторения знаков препинания и перевода строки.Я сохранил оригинальную строку максимально полно.

use strict;
use warnings;

my $replace = shift || "";
my @all;
my %count;
while (<DATA>) {
    for (split / +/) {
        my $word = s/[^A-Za-z'-]+//gr;
        $count{$word}++;
        if (lc $word eq lc $replace && (($count{$word} % 3) == 0)) {
            push @all, $word;
        }
        push @all, $_;
    }
}

print "@all" =~ s/\n /\n/gr;

__DATA__
Sed eleifend orci eget odio
consequat. Sed sagittis ipsum
eget pulvinar. Sed ut lacus
Sed luctus sollicitudin ligula
varius neque. Sed tincidunt
Sed mauris egestas eget. Sed
Curae; Sed aliquam enim Sed,
Sed dictum quis sem. Sed
volutpat tincidunt. Sed lacus.

Вывод:

Sed eleifend orci eget odio
consequat. Sed sagittis ipsum
eget pulvinar. Sed Sed ut lacus
Sed luctus sollicitudin ligula
varius neque. Sed tincidunt
Sed Sed mauris egestas eget. Sed
Curae; Sed aliquam enim Sed Sed,
Sed dictum quis sem. Sed
volutpat tincidunt. Sed Sed lacus.
0 голосов
/ 10 декабря 2011

После просмотра вашего комментария "просто выбранная пользователем строка не все повторяющиеся строки":

import re
g = 0

def double_third(fname, st):
    def smart_replace(m):
        global g
        g += 1
        if g % 3 == 0:
            return "%s %s" % (st, st)
        else:
            return st

    with open(fname) as f:
        print re.sub(st, smart_replace, f.read())

double_third('file.txt', 'Sed')
...