如何使用 awk 替换字段 1 中最后一次出现的特定字符

如何使用 awk 替换字段 1 中最后一次出现的特定字符

我试图使用 awk 将第一个字段中最后出现的句点替换为分号。字段分隔符也是分号。

(\.)(?!.*\1)在 regex101.com 上作为正则表达式进行了测试,当我提供“abcmp3”作为输入时,它正确地突出显示了最后一次出现的句点。

我在 awk 中尝试过以下操作:

awk 'BEGIN{FS=OFS=";"} {gsub(/(\.)(?!.*\1)/, ";", $1)} 1'

它不能取代任何东西。

我将不胜感激任何能对此提供帮助的人。

答案1

AFAIK,没有 awk 的实现支持 PCRE 环视,例如(?!re).

在 GNU awk(又名 gawk)中,使用根子函数,您可以贪婪地捕获句号之前的所有内容,并在替换中将其反向替换:

$ echo 'foo.bar.baz;something;else' | 
    gawk 'BEGIN{OFS=FS=";"} {$1 = gensub(/(.*)\./,"\\1;","1",$1)} 1'
foo.bar;baz;something;else

可移植的是,您可以使用匹配函数,再次进行贪心匹配,然后选出句号之前和之后的子字符串:

$ echo 'foo.bar.baz;something;else' | 
    mawk 'BEGIN{OFS=FS=";"} match($1,/.*\./){$1 = substr($1,1,RLENGTH-1) ";" substr($1,RLENGTH+1)} 1'
foo.bar;baz;something;else

使用 GNU awk,您可以(同样不可移植)match通过其可选的数组参数使用捕获和反向替换:

$ echo 'foo.bar.baz;something;else' | 
    gawk 'BEGIN{OFS=FS=";"} match($1,/(.*)\.(.*)/,a){$1 = a[1] ";" a[2]} 1'
foo.bar;baz;something;else

由于lookahead与perl兼容,您当然可以使用perl(尽管可能没有捕获和反向引用\.,这在任何情况下都显得有些过分):

$ echo 'foo.bar.baz;something;else' | 
    perl -F';' -pe '$_ = join ";", $F[0] =~ s/\.(?!.*\.)/;/r, @F[1..$#F]'
foo.bar;baz;something;else

磨坊主与 awk 类似,sub并且gsub像 GNU awk 一样gensub,支持捕获和反向引用:

$ echo 'foo.bar.baz;something;else' | 
    mlr --nidx --fs ';' put '$1 = sub($1,"(.*)\.","\1;")'
foo.bar;baz;something;else

据我所知,它目前不支持环视。

答案2

怎么样sed?就您而言,您很幸运能够在领域 1 工作:

sed 's/\.\([^.]*;\)/;\1/'

相关内容