0

次のような文字列がある場合:

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

p{n} の各インスタンスを別の値に置き換えるために sed (または実際には何か) を使用するにはどうすればよいですか? 結果は次のようになります。

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」に置き換えることになり、その後の置換は行われません。

Bob と Bob1 は Bob11 を訪問します。Bob は Bob11 の父親です

私が来た最も近いものは次のようなものです

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

これには 2 つの問題があります。末尾の文字 (スペース、句読点) を消費することと、行末の p{n} に一致しないことです。交換する必要があるすべてをループした後:

ボバンド・ジェネアがp111の父ポール・ボビスを訪ねる

他の変数に挿入せず、末尾の数字以外の文字を消費せずに、置き換える必要があるものを見つける方法を知っている人はいますか?

ありがとう。

4

3 に答える 3

2

もちろん。トリックは、エスケープされた括弧で区切られ、後方参照を使用して置換文字列に取り込まれる、一致したグループを使用して失いたくないものをすべて保持することです\1, \2, ..., \9:

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

別の方法であるlookaheadsもあります。これは、お使いのバージョンの で使用できる場合と使用できない場合があります。使用できるsed場合は、正規表現構文の「perl モード」を有効にする必要があります。

于 2012-06-25T10:21:48.403 に答える
0

これは私のために働く:

sed s/p1\\b/Bob/g

\b は、単語境界を表すゼロ幅アサーションです。

于 2012-06-25T18:46:15.283 に答える
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

これは、アレイの構築方法に応じて、そのままで機能する場合と機能しない場合があることに注意してください。私の実装では、返される順序がたまたま '111'、'11'、'1' であるため、r の反復は機能しますが、これは明確に定義された動作ではありません。データ ファイルを配列に読み込むのではなく、毎回読み込むことで、置換の順序を強制することができます。

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
}
于 2012-06-25T14:27:13.560 に答える