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

时间:2012-06-25 10:02:24

标签: regex bash sed

如果我有一个字符串:

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`

我最终用“Bob”替换每次出现的“p1”,并且不会发生后续替换:

Bob和Bob1将访问Bob11。 Bob是Bob11的父亲

我最接近的是

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

这有两个问题:它使用尾随字符(空格,标点符号),并且它与行末尾的p {n}不匹配。循环遍历需要更换的所有内容后:

Boband Janeare将访问p111的父亲Paul Bobis

任何人都知道如何找到我需要替换的内容,而不是插入到其他变量中,而不是使用尾随的非数字字符?

感谢。

3 个答案:

答案 0 :(得分:2)

不确定。诀窍是使用匹配的组保留您不想丢失的任何内容,由转义括号分隔,并使用反向引用\1\2,...,{{1}进入替换字符串}:

\9

还有一种替代方法lookaheads,可能在您的s/p1\([^0-9]\)/Bob\1/g 版本中可用,也可能不在,如果是,则需要启用其“perl模式”的正则表达式语法。< / p>

答案 1 :(得分:0)

您可以构建一个包含所需替换项的简单文件,将其命名为data

1 Bob
11 Jane
111 Paul

然后使用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

这要求您在构造查找文件时要小心,在这种情况下,要求数据行与上面给出的相反。如果您更喜欢添加单词分隔符,则可能更容易使用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
}

答案 2 :(得分:0)

这对我有用:

sed s/p1\\b/Bob/g

\ b是一个零宽度断言,代表字边界。