regex 使用sed替换变量数据时保留尾随字符

dzjeubhm  于 2023-10-22  发布在  其他
关注(0)|答案(4)|浏览(81)

如果我有一个字符串像这样:

p1 and p11 are going to visit p111. p1 is the father of p111

我如何使用sed(或者其他东西)来用不同的值替换p{n}的每个示例?所以结果会是这样的:

Bob and Jane are going to visit Paul. Bob is the father of Paul

基本上,我正在寻找一种方法来告诉sed,“精确地找到p{n}后面的任何数字,并用$var替换它,但不要替换{n}后面的东西。
如果我做一些简单的事情,

text="p1 and p11 are going to visit p111. p1 is the father of p111"
text=`echo "$text" | sed s/p1/Bob/g`

最后,我将每次出现的“p1”替换为“Bob”,并且不会发生后续替换:
鲍勃和鲍勃1打算去拜访鲍勃11。鲍勃是鲍勃11的父亲
我最接近的感觉是

text=`echo "$text" | sed 's/p1[^0-9]/bob/g'`

这有两个问题:它占用尾随字符(空格、标点符号),并且不匹配行尾的p{n}。在遍历了所有需要替换的内容之后:
鲍勃和简打算去拜访保罗·鲍勃,他是p111的父亲。
有人知道我如何找到我需要替换的东西,而不是插入到其他变量中,并且不消耗尾随的非数字字符吗?
谢谢.

ogsagwnx

ogsagwnx1#

当然。诀窍是使用匹配的组来保留任何你不想丢失的东西,用转义括号分隔,并使用反向引用\1\2,.,\9带入替换字符串:

s/p1\([^0-9]\)/Bob\1/g

还有一种替代方法lookaheads,它可能在您的sed版本中可用,也可能不可用,如果可用,则需要启用正则表达式语法的“perl模式”。

7gcisfzg

7gcisfzg2#

这对我很有效:

sed s/p1\\b/Bob/g

\B是代表字边界的零宽度Assert。

gmxoilav

gmxoilav3#

您可以构建一个包含所需替换的简单文件,称之为data
然后使用awk读取:

awk 'BEGIN{ while( getline d < "data" ) { split(d,a); r[a[1]]=a[2]}}
  { for( i in r ) gsub( "p"i, r[i])}1' input

请注意,这可能会也可能不会按原样工作,这取决于数组的构建方式。在我的实现中,r的迭代是有效的,因为返回的顺序恰好是'111','11','1',但这肯定不是定义良好的行为。您可以通过每次阅读数据文件而不是将其阅读到数组中来强制执行所需的替换顺序:

awk '{
  while( getline d < "data" ) { 
    split( d,a ); 
    gsub( "p"a[1],a[2])
  }
  close("data")}1' input

这要求您在构造查找文件时要小心,在这种情况下,要求数据行与上面给出的数据行相反。如果你更喜欢添加一个单词“candy”,使用perl可能更容易:

use autodie;
open my $f, "<", "data";
while(<$f>) {@a = split; $n{$a[0]} = $a[1]}
while(<>) {
  foreach $i (keys %n ) { s/p$i(\W)/$n{$i}$1/g }
  print
}
1szpjjfi

1szpjjfi4#

一行程序调用sed 3次,以相反的顺序替换p111,p11,p1。

echo "grep p1 and p11 are going to visit p111. p1 is the father of p111"|sed 's/p111/Paul/g'|sed 's/p11/Jane/g'|sed 's/p1/Bob/g'

相关问题