2012-06-25 19 views
0

如果我有這樣的字符串:保留尾部字符使用時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` 

我最終取代「P1」隨着每一次出現「鮑勃」,沒有後續的替代可以發生:

Bob和Bob1打算拜訪Bob11。 Bob是Bob11

的父親

我來最接近的是一樣的東西

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

這有兩個問題:它消耗的尾隨字符(空格,標點),並且它不匹配p {在一行的結尾處。通過需要更換所有循環後:

Boband Janeare要去拜訪保羅博維斯P111

任何人的父親有一個想法,我怎麼能找到我所需要更換,而不是插入其它變量,不消耗尾隨的非數字字符?

謝謝。

+0

爲什麼不先替換'p111',然後'p11',然後'p1'? – Shahbaz

回答

2

當然。關鍵是要保護什麼,你不希望使用匹配組,由轉義的括號分隔的損失,並投入使用反向引用\1\2替換字符串,...,\9

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

還有另一種方法,lookaheads,它可能會或可能不會在您的sed版本中可用,如果是,則需要啓用正則表達式語法的「perl模式」。

+0

爲了讓我工作起來,我遇到了一些麻煩,但Google告訴我這是我尋找的方法。謝謝。 –

+0

@MikeMitchell - 如果正則表達式直接是命令行的一部分,則需要轉義反斜槓,這意味着每次輸入兩次。 –

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 
} 
0

這個工作對我來說:

sed s/p1\\b/Bob/g 

\ b是零寬度斷言站立字邊界。