在每行找到第 n 个匹配后替换模式?

在每行找到第 n 个匹配后替换模式?

我有一个包含行的文件:

india;austria;japan;chile
china;US;nigeria;mexico;russia

我想用 eg 替换每行上出现的所有分号;NEW;,但仅从第二次出现开始。结果应该是这样的:

india;austria;NEW;japan;NEW;chile
china;US;NEW;nigeria;NEW;mexico;NEW;russia

我用 gsub 尝试过此操作,但它替换了所有发生的情况: awk '/;/{gsub(/;/,";NEW;") }{print}'

答案1

awk解决方案更长,但更容易使其通用:

awk -F\; '{for(i=1;i<NF;i++)printf"%s;%s",$i,(i>=2)?"NEW;":"";print$NF}' replacefile

也可以这样做sed,使用命令进行循环t并始终将第二个(或您想要的任何一个)分隔符替换为一些临时标记(通常\n):

sed ':b;s/;/\n/2;tb;s/\n/;NEW;/g' replacefile

答案2

GNU sed 命令有一个标志s///可以执行此操作:

sed 's/;/;NEW;/2g' <<END
india;austria;japan;chile
china;US;nigeria;mexico;russia
END

输出

india;austria;NEW;japan;NEW;chile
china;US;NEW;nigeria;NEW;mexico;NEW;russia

https://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-命令

s命令后面可以跟零个或多个以下标志:

g

将替换应用于正则表达式的所有匹配项,而不仅仅是第一个。

数字

仅更换数字正则表达式的第 次匹配。注意:posix 标准没有指定当你混合g和时会发生什么数字修饰符,目前在 sed 实现中还没有达成广泛一致的含义。对于 GNU sed,交互定义为: 忽略之前的匹配数字th,然后匹配并替换所有匹配项数字日。

...

(强调我的)

答案3

我会分两步完成此操作:

首先,将所有分号替换为;NEW;

sed -e s/\;/\;NEW\;/g

;NEW;然后用分号替换第一个:

sed -e s/\;NEW\;/\;/

您可以使用管道在一行上执行两项替换。这是一个例子:

$ more replacefile 
india;austria;japan;chile;
china;US;nigeria;mexico;russia
$ cat replacefile |sed -e s/\;/\;NEW\;/g  |sed -e s/\;NEW\;/\;/
india;austria;NEW;japan;NEW;chile;NEW;
china;US;NEW;nigeria;NEW;mexico;NEW;russia

答案4

我可以用更多代码来完成,但没有循环!

数据

china;US;nigeria;mexico;russia
iindia;austria;japan;chile

脚本

BEGIN{ FS=";" }{
    insert=$param
    ix=index($0, insert) + length(insert)

    if (NF <= $param) {
            rest = substr($0,ix,length($0))
            gsub(";",";NEW;",rest)
            line = substr($0,0,ix) rest

            gsub(";;",";",line)
            gsub(";$","",line)
            print line

} else {print}}

例子

 Microknoppix v # awk -f replaceNth.awk -v param=2 countries
 china;US;NEW;nigeria;NEW;mexico;NEW;russia
 iindia;austria;NEW;japan;NEW;chile

相关内容