Regex & Sed / Perl: Başında başka bir kelime bulunmayan kelimeyi eşleştir


11

Önünde belirli bir kelimesi olmayan bir kelimenin tüm tekrarlarını kullanmak sedveya perldeğiştirmek istiyorum .

Örneğin, bir filmin çizimini içeren bir metin dosyam var ve bir karakterin soyadının tüm tekrarlarını ilk adlarıyla değiştirmek istiyorum, ancak yalnızca adlarının soyadından hemen önce gelmemesi durumunda.

Örnek metin şöyle görünebilir:

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

Bunun gibi görünmesini istiyorum:

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

Sadece yaparsam sed 's/Smith/John/' file, o zaman olurdu:

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

Soyadından önce gelen ilk ad her zaman aynı olacaktır. Ben uğraşmak zorunda değilsiniz John Smithve Frank Smith. Bundan önce olmayan bir eşleşme yoluna ihtiyacım Smithvar John.


Hangi sed hakkında konuşuyorsun?
Ignacio Vazquez-Abrams

Linux'ta GNU sed 4.2.1
jonescb

Yanıtlar:


8

Düzenli ifadelerin arkasına bakabildiği herhangi bir dilde kolay olurdu. Tabii ki, Perl listede ilk:

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

Zayıf nokta “John” ve “Smith” arasında birden fazla kelime olmayan karaktere sahip olmaktır. Maalesef böyle bir nicelik +için \Wgündeme getireceğini hatası “Değişken uzunlukta uygulanmadı Geriye İlerleme”.


6

EDIT .. yorumunuzu yeniden .. İşte William Smith hakkında kendini ilgilendirmeyen yeni bir komut dosyası. Smith (değişmeden) olarak tuttuğu kalıpları geçici olarak gizler .

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

Bay Bay Bayan hakkında endişeleriniz varsa ... o zaman bu işe yarar.

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

William'a adını veya listesine ekleyerek hitap edebilirsiniz , örn.
sed -r 's/\<(William|John|...


Bu orjinal senaryo

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

Bu işe yarıyor, ancak bulduğum tek sorun, Smith'ten önceki kelime büyük harfle yazılmışsa (örneğin, bir cümledeki ilk kelimeden sonra gelirse) eşleşmediğiydi. İnsan yapımı perl çözümünün, başka durumlarda başarısız olsa bile, bu sorunu yoktur. Neyse ki, metin dosyamda Bay veya aynı soyadına sahip kişiler yok.
jonescb

Evet teşekkürler ... Değiştirilmiş bir senaryo yayınladım ...
Peter.O

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

(), Soyadı olmayan bir LastName'den önce yakalar, böylece yedekte geri gönderilirler.

Düzenle

@ Manatwork, Gilles

Haklısın. Peki ya

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

Bu hile gibi görünüyor.


Bu isimden önce başka bir kelime yoksa başarısız olur, örneğin “Smith ve Jane Johnson Smith'in arabası hakkında konuşurlar.”
manatwork

2
[^John]biri olmalıdır bir karakter eşleşir J, o, hveya n. Şüphelendiğin şey bu. Düzenli ifadelerde olumsuzlama yapısı yoktur (Perl vardır (?!…)ve (?<!…)ancak bunu bir olumsuzlama olarak görürseniz, muhtemelen beklediğinizi yapmayacaktır).
Gilles 'SO- kötü olmayı bırak'

@Juaco: Take-2'niz çalışıyor, ancak beklenmedik verilere karşı hassas. Ben benzer bir yöntem (biraz isteksiz olsa da) kullandım çünkü sedşişkin sed mantık için yapar olmadan kullanmak ... temp1neredeyse her zaman iyi olacak, ama! O otobüse dikkat et. Bu olasılığı azaltmak için, Latin-Script metin dosyalarında (neredeyse) hiçbir zaman oluşmayan karakterleri, örneğin Hex değeri \ x01 \ x02 veya bunların kombinasyonları veya belki de \ xe188b4 UTF-8 yerel ayarının ((- ETİYOPİK HAZIR GÖRMEK) .. örn. echo -e 'Z' |sed 's/./\xe1\x88\xb4/'=> yerel ayar UTF-8 olduğunda ..
Peter.O
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.