Grep'te açgözlü olmayan bir maç nasıl yapılır?


Yanıtlar:


276

Açgözlü olmayan (veya tembel) bir eşleşme arıyorsunuz. Düzenli ifadelerde açgözlü olmayan bir eşleşme elde etmek ?için niceleyiciden sonra değiştiriciyi kullanmanız gerekir . Örneğin değiştirebilir .*için .*?.

Varsayılan olarak grep, açgözlü olmayan değiştiricileri desteklemez, ancak grep -PPerl sözdizimini kullanmak için kullanabilirsiniz.


3
eegg: dot tüm değiştirici çok satırlı olarak da bilinir. "" Değiştiren bir değiştiricidir. yeni satırları içerecek şekilde davranışı eşleştirin (normalde içermez). Grep'te böyle bir değiştirici yoktur, ancak pcregrep'de vardır .
A. Wilson

1
Düzeltme: Onu destekleyen regex lezzetlerinin çoğunda, .yeni satırlarla eşleşmeye izin veren moda DOTALL veya tek satır modu denir ; Ruby ona çok satırlı diyen tek kişidir . Diğer tatlarda, çok hatlı , çapaların ( ^ve $) çizgi sınırlarında eşleşmesini sağlayan moddur . Ruby'nin eşdeğer bir modu yoktur, çünkü Ruby'de her zaman bu şekilde çalışırlar.
Alan Moore

5
-Püzerimde yepyeni bir şeydi, yıllardır mutlu bir şekilde selamlıyorum ve sadece -Eboşa harcanan yıllar ... - Kendine not: Man sayfalarını (daha da fazla!) Normal bir şey olarak tekrar okuyun, asla yeterli anahtar ve seçeneği sindirmezsiniz.
ocodo

29
Bazı platformlarda (Mac OS X gibi) grepdesteklenmez -P, ancak kullanırsanız aynı sonucu elde etmek için deseni egrepkullanabilirsiniz .*?. egrep -o 'start.*?end' text.html
SaltyNuts

4
@SaltyNuts yorumunun bir uzantısı olarak, Mac OS X desteklemez -Pancak -Ebu egrepnedenle önerilen .*?işler gayet iyi çalışır.
Fredrik Erlandsson

83

Aslında .*?sadece çalışıyor perl. Eşdeğer grep genişletilmiş regexp sözdizimi ne olacağını emin değilim. Neyse ki grep ile perl sözdizimini kullanabilirsiniz , grep -Pancak işe yarayacak grep -Eolanla aynıdır egrep(açgözlü olurdu).

Ayrıca bkz: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html


9
grep -PGNU grep 2.9'da çalışmıyor - sadece denedi (hata yapmaz, sadece sessizce uygulanmaz ?. Intertestly de sınıf değil örneğin:env|grep '[^\=]*\='
roberto tomás

2
Darwin / OS X 10.8 Mountain Lion'da bir grep -Pseçenek veya pgrepkomut yok , ama egrepharika çalışıyor.
Steve HHH

2
pgrepOS X 10.9 kutumda bir komut var, ancak amacı "süreçleri ada göre bulmak veya işaretlemek" olan tamamen farklı bir program.
Desty

@ robertotomás Burada 6 yaşındaki bir yoruma yanıt, ama .... Ben de bunu düşündüm ve sonra birden fazla açgözlü olmayan maçlar alıyordu fark etti. Örneğin, renkli bir terminalde bu "echo" bbbbb "| grep -P 'b. *? b'` 2 eşleşme döndürür.
zzxyz

12

Bu konuda şeyler denedikten sonra çalışan benim grep:

echo "hi how are you " | grep -shoP ".*? "

Satırlarınızın her birine bir boşluk eklediğinizden emin olun

(Mine, kelimeleri tükürmek için satır satır arandı)


3
-shoPgüzel anımsatıcı :)
Mariusz

echo "bbbbb" | grep -shoP 'b.*?b'biraz öğrenme deneyimidir. Benim için açıkça tembel olarak da işe yarayan tek şey.
zzxyz

12

grep

Açgözlü olmayan eşleşme grepiçin reddedilen bir karakter sınıfı kullanabilirsiniz. Başka bir deyişle, joker karakterlerden kaçınmaya çalışın.

Örneğin, jpeg dosyalarına yapılan tüm bağlantıları sayfa içeriğinden almak için şunu kullanırsınız:

grep -o '"[^" ]\+.jpg"'

Birden fazla hatla başa çıkmak için önce girişi boruya geçirin xargs. Performans için kullanın ripgrep.


3

Kısa cevap bir sonraki normal ifadeyi kullanmaktır:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - bu çok satırlı bir maç yapar
  • . *? - herhangi bir karakteri tembel bir şekilde birkaç kez eşleştirir (minimum eşleşme)

(Daha az) daha karmaşık bir cevap:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Bu, aşağıdaki metinde car1 ve car2 ile eşleşmeyi mümkün kılacaktır

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) bir yakalama grubunu temsil eder
  • \ 1 bu bağlamda, 1 numaralı grup yakalama ile en son eşleşen sametext ile eşleşir

1

Maalesef 9 yıl geç kaldım, ancak bu 2020'de izleyiciler için işe yarayabilir.

Diyelim ki böyle bir çizginiz var "Hello my name is Jello". Şimdi ile başlayan 'H've 'o'aralarındaki herhangi bir sayıda karakterle biten kelimeleri bulmak istiyorsunuz . Ve çizgiler istemiyoruz, sadece kelimeler istiyoruz. Bunun için şu ifadeyi kullanabiliriz:

grep "H[^ ]*o" file

Bu tüm kelimeleri döndürecektir. Bunun çalışma şekli şudur: Aradaki boşluk karakteri yerine tüm karakterlere izin verir, böylece aynı satırda birden çok kelimeden kaçınabiliriz.

Artık boşluk karakterini istediğiniz herhangi bir karakterle değiştirebilirsiniz. İlk satırın olduğunu varsayalım "Hello-my-name-is-Jello", o zaman ifadeyi kullanarak kelimeler alabilirsiniz:

grep "H[^-]*o" file

0

Biraz ölü bir yazı olduğunu biliyorum ama bunun işe yaradığını fark ettim. Hem temizliği hem de temizlemeyi çıktımdan kaldırdı.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
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.