Regex&Sed / Perl:ISNの前に別の単語がない単語に一致


11

前に特定の単語がない単語をすべて使用sedまたはperl置換したい。

たとえば、映画のプロットが含まれているテキストファイルがあり、出現するすべてのキャラクターの姓を名に置き換えたいのは、姓が姓の直前にない場合のみです。

サンプルテキストは次のようになります。

John Smith and Jane Johnson talk about Smith's car.

私はそれをこのように見せたいです:

John Smith and Jane Johnson talk about John's car.

私がちょうどするならsed 's/Smith/John/' file、私は持っているでしょう:

John John and Jane Johnson talk about John's car.

姓の前にある名は常に同じになります。私はに対処する必要はありませんJohn SmithFrank Smith。私SmithJohnそれに先行していないマッチする方法が必要です。


どのsedについて話しているのですか?
Ignacio Vazquez-Abrams

Linux上のGNU sed 4.2.1
jonescb

回答:


8

正規表現が後ろを見ることができる言語であれば、簡単です。もちろん、Perlはリストの最初です。

perl -pe 's/(?<!John\W)Smith/John/g' <<< "John Smith and Jane Johnson talk about Smith's car."

弱点は、「John」と「Smith」の間に単語以外の文字が複数あることです。残念ながら+forのような数量詞\Wは「可変長後読みが実装されていません」というエラーを発生させます。


6

EDIT .. re your comment ..これは、(たとえば)William Smithに関係しない新しいスクリプトです。スミス(変更なし)として保持するパターンを一時的に難読化します。

sed -r 's/\<(John) (Smith)\>/\1\x01x\2/g; 
        s/\<Smith\>/John/g;  s/\x01x/ /g'

ミセス夫人について心配している場合...これはうまくいきます。

sed -r 's/\<(John|((M(r|rs|s))\.?)) (Smith)\>/\1\x01x\5/g
        s/\<Smith\>/John/g; s/\x01x/ /g'

ウィリアムの名前をorリストに追加することで、ウィリアムに対応できます。
sed -r 's/\<(William|John|...


これは元のスクリプトです

sed -r 's/(^|[[:punct:]] |\<[a-z]+ )(Smith\>)/\1John/'

これは機能しますが、私が見つけた1つの問題は、スミスの前の単語が大文字である場合(たとえば、文の最初の単語の後にある場合)、一致しないことです。manatworkによるperlソリューションは、他の状況で失敗するとしても、その問題はありません。幸い、私のテキストファイルには、氏や同じ姓の人々のようなタイトルがありません。
jonescb

はい、ありがとう...私は修正されたスクリプトを投稿しました...
Peter.O

1
 sed -r 's/([^John] )Smith/\1John/g;s/([^Jane] )Johnson/\1Jane/g'

()は、LastNameの前に非Firstnameをキャプチャするので、それらは置換で後方参照されます。

編集

@ manatwork、gilles

あなたが正しい。どう?

sed -r 's/(John Smith)/temp1/g;s/Smith/John/g;s/temp1/John Smith/g'

これでうまくいくようです。


名前の前に他の単語がない場合、これは失敗します。たとえば、「スミスとジェーンジョンソンは、スミスの車について話します。」
manatwork

1
[^John]いずれかでなければなりません1つの文字が一致しJohまたはn。これがあなたの意図したものではないかと思います。正規表現(Perlは持っているには否定構築物は存在しない(?!…)(?<!…)、しかし、あなたが否定と考えるならば、それはおそらくあなたが期待しないだろう)。
Gilles 'SO-悪をやめなさい' 11/11/6

@Juaco:take-2は機能しますが、予期しないデータの影響を受けやすくなります。私は同様の方法を使用しました(少ししぶしぶとはいえ)、sedそれなしで使用するとsedロジックが肥大化します... temp1ほとんどの場合は問題ありませんが!そのバスに気をつけろ。この可能性を軽減するには、ラテンスクリプトのテキストファイルでは(ほとんど)決して発生しない文字(16進値\ x01 \ x02、またはそれらの組み合わせ、またはおそらく\ xe188b4 UTF-8ロケール(ሴ- ETHIOPIC SYLLABLE SEE).. eg。 echo -e 'Z' |sed 's/./\xe1\x88\xb4/'=> ロケールがUTF-8の場合..
Peter.O
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.