每三次出现一个字符串

时间:2011-12-09 20:27:40

标签: perl bash command-line sed awk

我有一个这样的文件:

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 个答案:

答案 0 :(得分:6)

Perl one-liner可以通过使用/e修饰符实现这一点,它允许基于逻辑的替换:

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

解释

  • <强> -pi.bak

    逐行就地编辑文件。备份存储在 file.txt.bak

  • BEGIN 阻止

    指定$str的值,仅执行一次

  • <强> s/PATTERN/REPLACEMENT/ge

    $_中所有匹配的正则结构替换,逐行替换。 REPLACEMENT 评估为Perl代码。

  • <强> (?<=$str)

    固定长度的后视断言

  • <强> ++$cnt % 3 ? "" : " $str"

    每隔三场比赛,追加" $str",否则不追加任何内容

答案 1 :(得分:3)

你也可以使用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.

答案 2 :(得分:0)

看到你的评论说“只是一个用户选择的字符串而不是所有重复的字符串”:

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

答案 3 :(得分:0)

此脚本将参数作为要乘的单词。剥离标点符号将使计数准确,并避免重复标点符号或换行符。我尽可能完整地保留了原始字符串。

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.

答案 4 :(得分:0)

这可能对您有用:

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. 在全球范围内用所选字符串替换不太可能的字符。

答案 5 :(得分:-1)

s/(\bSed\b.*?\bSed\b.*?\bSed\b)/$1 Sed/gsm