Açgözlü ve isteksiz karşılaştırıcılar


358

Düzenli ifadeler üzerinde bu mükemmel öğreticiyi buldum ve sezgisel olarak "açgözlü", "isteksiz" ve "iyelik" nicelleştiricilerin ne yaptığını anlasam da, anlayışımda ciddi bir delik var gibi görünüyor.

Özellikle, aşağıdaki örnekte:

Enter your regex: .*foo  // greedy quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfooxxxxxxfoo" starting at index 0 and ending at index 13.

Enter your regex: .*?foo  // reluctant quantifier
Enter input string to search: xfooxxxxxxfoo
I found the text "xfoo" starting at index 0 and ending at index 4.
I found the text "xxxxxxfoo" starting at index 4 and ending at index 13.

Enter your regex: .*+foo // possessive quantifier
Enter input string to search: xfooxxxxxxfoo
No match found.

Açıklama bahseder yeme , harfler edilmiş Tüm giriş dizesini tüketilen matcher, kapalı destek , "foo" nin en sağdaki oluşum olmuştur regurgitated vb

Ne yazık ki, güzel metaforlara rağmen, hala kim tarafından ne yendiğini anlamıyorum ... Normal ifadelerin motorlarının nasıl çalıştığını açıklayan (kısaca) başka bir öğretici biliyor musunuz ?

Alternatif olarak, bir kişi aşağıdaki paragrafı biraz farklı bir ifadeyle açıklayabilirse, bu çok takdir edilecektir:

İlk örnek, sıfır veya daha fazla kez "herhangi bir şey" bulmak için açgözlü niceleyiciyi kullanır. * Ve ardından "f" "o" "o" harfleri. Nicelik belirteci açgözlü olduğu için, ifadenin. * Kısmı önce tüm girdi dizesini yer. Bu noktada, genel ifade başarılı olamaz, çünkü son üç harf ("f" "o" "o") zaten tüketilmiştir ( kim tarafından? ). Böylece eşleştirici yavaş yavaş ( sağdan sola mı? ) "Foo" nun en sağdaki oluşumunun yeniden oluşmasına ( bu ne anlama geliyor? ) Kadar her seferinde geri çekilir , bu noktada maç başarılı olur ve arama sona erer.

Bununla birlikte, ikinci örnek isteksizdir, bu yüzden ilk önce ( kim tarafından? ) "Hiçbir şey" tüketerek başlar . Dizenin başında "foo" görünmediğinden , ilk maçı 0 ve 4'te tetikleyen ilk harfi (bir "x") yutmak ( kim yutar?) giriş dizesi bitene kadar. 4 ve 13'te başka bir maç bulur.

Üçüncü örnek, nicelik belirteci sahip olduğu için eşleşme bulamıyor. Bu durumda, giriş dizesinin tamamı. * +, ( Nasıl? ) Tarafından kullanılır ve ifadenin sonunda "foo" yu tatmin edecek hiçbir şey kalmaz. Hiçbir şeyi geri çekmeden ele geçirmek istediğiniz durumlar için iyeliksel bir nicelik belirteci kullanın ( geri çekilme ne demektir? ); eşleşmenin hemen bulunmadığı durumlarda eşdeğer açgözlü niceleyiciden daha iyi performans gösterir.


22
Maksimal nicelik gibi *, +ve ?vardır açgözlü. Minimal nicelik gibi *?, +?ve ??vardır tembel. İyelik nicelik gibi *+, ++ve ?+vardır yapışkan.
tchrist

6
Bu soru, Yığın Taşması Düzenli İfade SSS'ye "Nicelleştiriciler> Farklılıklar hakkında daha fazla ..." başlığı altında eklenmiştir .
aliteralmind

İlgi çekici olanlar: Java ™ Öğreticileri - Açgözlü, İsteksiz ve İyeliksel Niceleyiciler Arasındaki Farklar - Bölümü görmek için aşağı kaydırın.
Guy Coder

Yanıtlar:


495

Bir şans vereceğim.

Bir açgözlü mümkün olduğunca miktar belirleyici ilk maçlar. Yani .*tüm dizeyle eşleşir. Ardından eşleştirici faşağıdakileri eşleştirmeye çalışır , ancak hiç karakter kalmaz. Açgözlü niceleyicinin bir tane daha az karakterle eşleşmesi "dizgileri" (dizenin sonunda "o" yı eşsiz bırakır). Bu hala fnormal ifadedeki ile eşleşmiyor , bu yüzden açgözlü niceleyicinin tekrar bir daha az karakterle eşleşmesini sağlıyor (dizenin sonundaki "oo" yi eşleşmiyor). Bu halaf normal ifadedeki ile eşleşmiyor , bu yüzden bir adım daha geri gidiyor (dizenin sonundaki "foo" yu eşsiz). Şimdi, eşleştirici nihayet maçları fregex,ooeşleşir. Başarı!

Bir isteksiz mümkün olduğunca az "olmayan açgözlü" nicelik ilk maçlar ya. Yani .*ilk başta hiçbir şey eşleşmez, tüm dizeyi eşsiz bırakır. Ardından eşleştirici faşağıdakileri eşleştirmeye çalışır , ancak dizenin eşleşmeyen kısmı "x" ile başlar, böylece çalışmaz. Böylece, eşleştirici geri teper, açgözlü olmayan niceleyiciyi bir karakterle eşleştirir (şimdi "x" ile eşleşir ve "fooxxxxxxfoo" 'yu ​​eşsiz bırakır). Daha sonra f, başarılı olan ve normal ifadedeki ove sonraki oile eşleşmeye çalışır. Başarı!

Örneğinizde, daha sonra aynı işlemi izleyen "xxxxxxfoo" dizesinin eşleşmeyen kısmı ile işleme başlar.

Bir iyelik nicelik sadece açgözlü nicelik gibi, ama geriye dönük izleme yok. Böylece .*, tüm dizeyi eşleştirmekle başlar ve hiçbir şeyi eşsiz bırakmaz. Sonra fnormal ifade ile eşleşecek hiçbir şey kalmadı . İyelik niceliğini geri takip etmediğinden, maç orada başarısız olur.


15
+1 İyi cevap. Ben sadece
eklerdim

@Anomie biraz geç ama iyelik kısmında, demek istediğini düşünüyorum Yani başlar .*+ ("+" dikkat edin)
RD

3
iyelik niceliği o zaman tam olarak ne yapar? eğer bu uyuşmuyorsa? (Yani anlamı ne, eğer karakterlerden sonra
olamazsanız

4
@relipse: Geri izlemenin yardımcı olmayacağını bildiğiniz bir durumda, muhtemelen .*+her şeyle eşleşen bir durumda kullanmazsınız . Örneğin, bir deseniniz [xyz]*foovarsa, x'lerin, y'lerin ve z'lerin bitle eşleştirilmesinin [xyz]*aşağıdaki foobitin eşleşmesine izin vermesinin bir yolu yoktur , böylece iyilik yaparak işleri hızlandırabilirsiniz.
Anomie

4
moodboom, iyelik niceleyicilerin basit açgözlü niceleyiciler tarafından üretilmeyecek bir eşleşme üreteceği sıfır vaka (matematiksel gerçek) vardır . Açgözlü niceleyiciler bir eşleşme ürettiğinde hiçbir eşleşme üretmeyecekleri durumlar vardır . Diğer TÜM durumlar için (açgözlü ve iyelik sahibi aynı sonuçları verir), iyelik niceliklendiriciler performans kazancı verir.
Wildcard

49

Sahneyi görselleştirmek sadece benim pratik çıktım

Görsel Resim


3
Bence son dava, iyelik, n geçişi olmamalı - sadece bir defada tüm ipi yakala.
Modlarınıza iyi davranın

@phyzome Sanırım şimdi iyi mi?
SIslam

1
Görsel açıklama için teşekkürler :)
Lars Moelleken

Olarak EXPRESSION .*?foo(), should't [f] [o] [o]dikdörtgenler sarı olabilir 5th pass?
19:45 tonix

1
@tonix evet! Sarı boyama ifadesinde eşleşti kısmı için yapılması gereken .*?foove .*+foo.
SIslam

24

Daha önce 'regurgitate' veya 'backing' terimlerini tam olarak duymadım; bunların yerini alacak olan cümle "geri izleme" dir, ancak 'regurgitate', "geri izleme tekrar atılmadan önce geçici olarak kabul edilen içerik" için olduğu kadar iyi bir cümle gibi görünür.

Normal regex motorları hakkında farkına varılması gereken en önemli şey, geri izleme yapıyor olmalarıdır: normal regex'in tüm içeriğini eşleştirmeye çalışırken potansiyel olarak, kısmi bir eşleşmeyi geçici olarak kabul edeceklerdir . Normal deneme ilk denemede tamamen eşleştirilemezse, normal ifade motoru eşleşmelerinden birinde geriye doğru hareket eder. Bu eşleştirme çalışacağız *, +, ?, münavebe veya {n,m}farklı tekrarlanmasını ve yeniden deneyin. (Ve evet, bu süreç olabilir uzun sürebilir.)

İlk örnek, sıfır veya daha fazla kez "herhangi bir şey" bulmak için açgözlü niceleyiciyi kullanır. * Ve ardından "f" "o" "o" harfleri. Nicelik belirteci açgözlü olduğu için, ifadenin. * Kısmı önce tüm girdi dizesini yer. Bu noktada, genel ifade başarılı olamaz, çünkü son üç harf ("f" "o" "o") zaten tüketilmiştir ( kim tarafından? ).

Son üç harf, f, o, ve ozaten başlangıçtaki tarafından tüketilen edildi .*kuralın kısmı. Bununla birlikte, normal ifadedeki bir sonraki öğenin fgiriş dizesinde hiçbir şey kalmaz. Motor , ilk eşleşmesinde geriye doğru hareket etmek zorunda kalacak .*ve sonuncusu hariç karakteri eşleştirmeyi deneyecek. ( Akıllı ve son üçü birden geriye dönük olabilir , çünkü üç gerçek terimi vardır, ancak bu düzeydeki uygulama ayrıntılarının farkında değilim.)

Böylece, eşleştirici yavaş yavaş ( sağdan sola mı? ) "Foo" nun en sağdaki oluşumunun yeniden yaratılmasına kadar ( bu ne anlama geliyor? )

Bu araçlar fooetmişti geçici zaman eşleşmesini de olmuştur .*. Bu girişim başarısız olduğu için normal ifade motoru daha az karakter içeriyor .*. Başarılı bir maç olsaydı önce.* bu örnekte, daha sonra motor muhtemelen kısaltarak çalışacaktı .*maçı (sağdan-sola-sen işaret gibi açgözlü bir eleme olduğu için,) o maçın edemedi ve eğer o zaman bulunmak zorunda kalabileceğini tüm girişler, bu eşleşti ne olduğunu yeniden değerlendirmek önce.* benim varsayımsal örnekte.

nokta başarılı olur ve arama sona erer.

Bununla birlikte, ikinci örnek isteksizdir, bu yüzden ilk önce ( kim tarafından? ) "Hiçbir şey" tüketerek başlar . Çünkü "foo"

Başlangıçtaki hiçbir şey tüketilmez .?*, bu da regex'in geri kalanının eşleşmesine izin veren her şeyi mümkün olan en kısa miktarda tüketir.

ipin başında görünmezse, yutmaya zorlanır ( kim yutar?)

Yine, .?*ilk regex'in mümkün olan en kısa eşleşmeyle eşleşmemesi durumunda ilk izlemeyi geri aldıktan sonra ilk karakteri tüketir. (Bu durumda, normal ifade motoru eşleşmeyi .*?soldan sağa doğru uzatır , çünkü .*?isteksizdir.)

ilk harfi 0 ve 4'te tetikleyen ilk harf ("x"). Test kablo demetimiz giriş dizgisi tükenene kadar işleme devam eder. 4 ve 13'te başka bir maç bulur.

Üçüncü örnek, nicelik belirteci sahip olduğu için eşleşme bulamıyor. Bu durumda, giriş dizesinin tamamı. * +, ( Nasıl? ) Tarafından kullanılır.

A .*+mümkün olduğunca tüketecek ve normal olarak bir maç bulamadığında yeni maçlar bulmak için geri gitmeyecek . İyelik formu backtracking gerçekleştirmek olmadığından, muhtemelen ile birçok kullanımı görmezsiniz .*+ziyade karakter sınıfları veya benzer kısıtlamalar,: account: [[:digit:]]*+ phone: [[:digit:]]*+.

Bu, normal ifade eşleşmesini büyük ölçüde hızlandırabilir, çünkü normal ifade motoruna, bir giriş eşleşmediğinde potansiyel eşleşmeler üzerinde asla geri adım atmaması gerektiğini söylüyorsunuz. (Eşleşen tüm kodu el ile yazmak zorunda olsaydınız, bu hiçbir zaman putc(3)bir giriş karakterini 'geri itmek' için kullanılmaya benzemez. Tek bir geri itme karakterinden daha iyi, tüm geri sıfıra geri sarabilir ve tekrar deneyebilirler. :)

Ancak, potansiyel hız artışlarından daha fazla, bu da tam olarak eşleşmeniz gerekenle eşleşen regex'ler yazmanıza izin verebilir. Ben kolay bir örnek ile geliyor sorun yaşıyorum :) ama iyelikli vs açgözlü niceleyiciler kullanarak bir regex yazmak size farklı maçlar verebilir ve bir veya diğeri daha uygun olabilir.

ifadenin sonundaki "foo" yu tatmin edecek hiçbir şey bırakmaz. Hiçbir şeyi geri çekmeden ele geçirmek istediğiniz durumlar için iyeliksel bir nicelik belirteci kullanın ( geri çekilme ne demektir? ); daha iyi performans gösterecek

Bu bağlamda "geri çekilmek", "geri takip" anlamına gelir - başarabilen veya edemeyen başka bir kısmi eşleşmeyi denemek için geçici bir kısmi eşleşme atma.

eşleşmenin hemen bulunmadığı durumlarda eşdeğer açgözlü nicelik belirteci.


2
Asla iyelikçi bir niceleyicinin açgözlü bir niceleyicinin yapmayacağı bir şeyle eşleşmeyeceğinden şüpheleniyorum. Aşağıdakilerin bunu kanıtladığına inanıyorum: Açgözlü bir niceleyici her zaman mümkün olduğunca eşleşir, daha sonra bir eşleşme bulamazsa geri döner. Bir iyelik niceliği mümkün olduğunca eşleşir, sonra bir eşleşme bulamazsa kapanır . Bu nedenle, açgözlü bir niceleyicinin, iyelikli niceleyicinin tersi ile eşleşmeyeceği bir şey olabilir, çünkü ikisi de "ağacı" aynı dizide ararlar, iyelik niceleyicisi daha kolay vazgeçer. ;)
Joker

2
Onaylandı: "Atomik gruplama ve iyelik nicelikleri bunun için: geri izlemeye izin vermeyerek verimlilik." regular-expressions.info gelen bu cevap açıklamada Yani "Ama daha fazla potansiyel hız ups daha, bu da size eşleşmesi gerekir tam olarak eşleşmesini regexs yazalım olabilir." aslında tam olarak doğru değil.
Joker

1
@Wildcard, yorumlar için teşekkürler; bu bir örnek bulmakta neden zorlandığımı açıklayabilir. Hehe.
Mart'ta sarnold

19

http://swtch.com/~rsc/regexp/regexp1.html

Bunun internetteki en iyi açıklama olduğundan emin değilim, ama oldukça iyi yazılmış ve uygun bir şekilde ayrıntılı ve tekrar geri gelmeye devam ediyorum. Kontrol etmek isteyebilirsiniz.

Daha üst düzey (daha az ayrıntılı açıklama) istiyorsanız, baktığınız gibi basit normal ifadeler için, normal bir ifade motoru geri izleme ile çalışır. Esasen, dizenin bir bölümünü seçer ("yiyor") ve normal ifadeyi o bölümle eşleştirmeye çalışır. Eşleşirse harika. Değilse, motor dizenin bölümü seçimini değiştirir ve olası her seçenek denenene kadar normal ifadeyi bu bölümle eşleştirmeye çalışır.

Bu işlem özyinelemeli olarak kullanılır: bir dizeyi belirli bir düzenli ifadeyle eşleştirme girişiminde, motor düzenli ifadeyi parçalara böler ve algoritmayı her parçaya ayrı ayrı uygular.

Açgözlü, isteksiz ve sahip olunan nicelik belirteçler arasındaki fark, motor ipin hangi kısmıyla eşleşmeye çalışacağını seçer ve ilk kez çalışmazsa bu seçimi nasıl değiştirirse girer. Kurallar aşağıdaki gibidir:

  • Açgözlü bir nicelik belirleyici, motora tüm dizeyle (veya en azından normal ifadenin önceki bölümleriyle zaten eşleşmemiş olanla) başlamasını ve normal ifadeyle eşleşip eşleşmediğini kontrol eder. Eğer öyleyse, harika; motor normal ifadenin geri kalanıyla devam edebilir. Değilse, tekrar dener, ancak kontrol edilecek dizenin bölümünden bir karakter (sonuncusu) kırpılır. Bu işe yaramazsa, başka bir karakteri, vb. Keser. Böylece, açgözlü bir niceleyici olası eşleşmeleri en uzuntan en kısaa doğru kontrol eder.

  • İsteksiz bir nicelik belirleyici, motora mümkün olan en kısa ip ile çalışmasını söyler. Eşleşirse, motor devam edebilir; değilse, denetlenen dizenin bölümüne bir karakter ekler ve bunu dener ve bir eşleşme bulana veya dizenin tamamı tükenene kadar devam eder. Böylece isteksiz bir nicelik belirleyici olası eşleşmeleri en kısatan en uzuna doğru kontrol eder.

  • Bir iyelik nicelik belirteci ilk denemede açgözlü bir nicemleyici gibidir: motora tüm dizeyi kontrol ederek çalışmasını söyler. Fark, eğer işe yaramazsa, sahip olunan nicelik belirteci eşleşmenin o anda ve orada başarısız olduğunu bildirir. Motor, incelenen dizenin bölümünü değiştirmez ve daha fazla deneme yapmaz.

Bu nedenle, iyelik nicelik eşleştirmesi eşleşmenizde başarısız olur: .*+eşleştiği tüm dizeye karşı kontrol edilir, ancak daha sonra motor bundan foosonra ek karakterler aramaya devam eder - ancak elbette onları bulamaz, çünkü zaten dizenin sonunda. Açgözlü bir nicelik belirleyici olsaydı, geriye doğru izler ve .*tek eşlemeyi bir sondan son karaktere, daha sonra üçüncü ila son karaktere, daha sonra dördüncü ila son karaktere kadar yapmaya çalışır. orada bir foosol sonra .*"dize önceki kısmı" yemiş.


1
Bu mükemmel bir kaynak. Devlet makine şemalarını seviyorum. :)
Regex Çaylak

@ Regex Rookie: Hoşunuza gitti :) Bu siteyi inceledikten sonra, amacının normal bir ifade motorunun alternatif bir uygulamasını tanıtmak olduğunu açıkça belirtmeliyim. I (kısmen) ve diğer cevapların tarif ettiği geri izleme algoritması yavaş yoldur; web sayfasında açıklanan NFA / DFA fikrinden tamamen ayrı bir algoritmadır. Geri izlemeyi anlamak daha kolaydır, bu nedenle normal ifadeler genellikle yeni başlayanlara bu şekilde açıklanır.
David Z

@David Zaslavsky: İyi açıklama. "Açgözlü bir nicelik belirteci, motora tüm dizeyle (veya en azından normal ifadenin önceki bölümleriyle eşleşmemiş olanların tümü ile başlamasını) söyler. Ayrıca isteksiz ve iyelik nicelikleri için de geçerlidirler. Bu, açıklamanızı örnek kalıplarımızı (". * Foo"; ". *? Foo"; ve ". * + Foo") yerine ("foo. *"; "Foo. *? "; ve" foo. * + ").
John Bentley

Aslında, xfooxxxxxxfoo eşleşir. * Foo normalde (bilgisayar bilimi anlamı) normal ifadenin. NFA, herhangi bir karakterle kendi aralarında dolaştığı ve sonra foo'ya atlayabileceği bir durum olacaktır. DFA, bu NFA'nın açık bir çevirisi olacaktır. 8 eyalette yapılabilir.
user4951

@JimThio evet, çünkü bu iyelikçi bir nicelik değil.
David Z

13

İşte Hücre ve Dizin konumlarını kullanarak benim almak ( Bir Hücreyi bir Dizin'den ayırmak için buradaki şekle bakın ).

Açgözlü - Açgözlü nicelik belirteci ve tüm normal ifadeyle mümkün olduğunca eşleştirin. Eşleşme yoksa, açgözlü nicelik belirteçte geriye doğru ilerleyin.

Girdi Dize: xfooxxxxxxfoo
Regex: . * Foo

Yukarıdaki Regex'in iki bölümü vardır:
(i) '. *' Ve
(ii) 'foo'

Aşağıdaki adımların her biri iki parçayı analiz edecektir. 'Pass' veya 'Fail' ile eşleşecek ek yorumlar parantez içinde açıklanır.

Adım 1:
(i). * = Xfooxxxxxxfoo - PASS ('. *', Açgözlü bir nicelik belirtecidir ve tüm Giriş Dizesini kullanır)
(ii) foo = Dizin 13'ten sonra eşleşecek karakter kalmadı - FAIL
Match başarısız oldu.

Adım 2:
(i). * = Xfooxxxxxxfo - PASS (Açgözlü nicelik belirtecinde geri izleme '. *')
( İi ) foo = o - FAIL
Eşleşme başarısız oldu.

Adım 3:
(i). * = Xfooxxxxxxf - PASS (Açgözlü nicelik belirtecinde geri izleme '. *')
( İi ) foo = oo - FAIL
Eşleşme başarısız oldu.

Adım 4:
(i). * = Xfooxxxxxx - PASS (Açgözlü nicelik belirtecinde geri izleme '. *')
( İi ) foo = foo - PASS
Raporu MAÇI

Sonuç: 1 maç (lar)
"xfooxxxxxxfoo" metnini 0 dizininden başlayıp 13 dizininden biterek buldum.

İsteksiz - İsteksiz nicelik belirteci ile mümkün olduğunca az eşleştirin ve tüm normal ifadeyi eşleştirin. eşleşme yoksa, isteksiz nicelik belirtecine karakterler ekleyin.

Girdi Dize: xfooxxxxxxfoo
Regex: .? * Foo

Yukarıdaki normal ifadenin iki bölümü vardır:
(i) '. *?' ve
(ii) 'foo'

Adım 1:.
*? = '' (boş) - PASS (İsteksiz nicelik belirteci ile mümkün olduğunca az eşleşme. *? '.' 'olan dizin 0 bir eşleşmedir.)
foo = xfo - FAIL (Hücre 0,1,2 - yani, 0 ve 3)
Eşleşme başarısız oldu.

Adım 2:.
*? = x - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '.' x 'olan 0 hücresi eşleşir.)
foo = foo - PASS
Rapor MAÇI

Adım 3:.
*? = '' (boş) - PASS (İsteksiz nicelik belirteci ile mümkün olduğunca az eşleşme. *? '.' 'olan Dizin 4 bir eşleşmedir.)
foo = xxx - FAIL (Hücre 4,5,6 - yani, 4 ve 7)
Eşleşme başarısız oldu.

Adım 4:.
*? = x - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4.)
foo = xxx - FAIL (Hücre 5,6,7 - yani 5 ile 8 arasında dizin)
Eşleşme başarısız oldu.

Adım 5:.
*? = xx - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4 - 5.)
foo = xxx - FAIL (Hücre 6,7,8 - yani 6 ile 9 arasında dizin)
Eşleşme başarısız oldu.

Adım 6:.
*? = xxx - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4 - 6.)
foo = xxx - BAŞARISIZ (Hücre 7,8,9 - yani 7 ve 10 arasındaki dizin)
Eşleşme başarısız oldu.

Adım 7:.
*? = xxxx - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4 - 7.)
foo = xxf - FAIL (Hücre 8,9,10 - yani 8 ile 11 arasında dizin)
Eşleşme başarısız oldu.

Adım 8:.
*? = xxxxx - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4 - 8.)
foo = xfo - FAIL (Hücre 9,10,11 - yani 9 ile 12 arasında dizin)
Eşleşme başarısız oldu.

Adım 9:.
*? = xxxxxx - PASS (İsteksiz niceleyiciye karakter ekleyin. *? '. Hücre 4 - 9 arası)
foo = foo - PASS (Hücre 10,11,12 - yani 10 ile 13 arasında dizin)
MATCH

Adım 10:.
*? - '(?.. *' Endeksi 13 boştur. = 'Maç isteksiz nicelik için mümkün olduğunca az) PASS (boş)'
foo = Hayır karakter maç için bıraktı - FAIL (maç için endeks 13 sonra hiçbir şey yoktur)
Eş başarısız oldu.

Sonuç: 2 maç (lar)
Dizin 0'dan başlayıp dizin 4'te biten
"xfoo" metnini buldum. Dizin 4'ten başlayıp dizin 13'te biten "xxxxxxfoo" metnini buldum.

İyelik - Mümkün olduğunca nicel nicel ile eşleştirin ve tüm normal ifadeyi eşleştirin. Geri izlemeyin.

Girdi Dize: xfooxxxxxxfoo
Regex: . * + Foo

Yukarıdaki normal ifadenin iki bölümü vardır: '. * +' Ve 'foo'.

Adım 1
:. * + = Xfooxxxxxxfoo - PASS (Mümkün olduğunca nicel niceleyiciyle
eşleştir '. *') Foo = Eşleşecek karakter kalmadı - FAIL (İndeks 13'ten sonra eşleşecek bir şey yok)
Maç başarısız oldu.

Not: Geri izlemeye izin verilmez.

Sonuç: 0 maç


1

Açgözlü: "mümkün olan en uzun karakter dizisiyle eşleş"

İsteksiz: "mümkün olan en kısa karakter dizisiyle eşleş"

İyelik: Bu, biraz açgözlüdür (açgözlü ve isteksizden farklı olarak) tüm regex için bir eşleşme bulmaya çalışır.

Bu arada: Hiçbir normal ifade kalıbı eşleştirici uygulaması geri izlemeyi kullanmaz. Tüm gerçek hayat patern eşleştiricisi son derece hızlı - neredeyse düzenli ifadenin karmaşıklığından bağımsız!


Bildiğim kadarıyla, çoğu genel kullanım uygulamaları, özelliklerle doludur, geri izleme kullanmamak imkansız hale geldi. Bu yüzden teoride, bazı durumlarda (üstel olarak) son derece yavaş olmalıdırlar. Ancak bu vakaların çoğu için kalıp eşleştiricide yerleşik özel optimizasyonlar vardır.
Robert

0

Açgözlü Niceleme , bir yineleme sırasında bir dizenin kalan onaylanmamış karakterlerinin tümünü kullanarak desen eşleşmesini içerir. Onaylanmamış karakterler etkin sırada başlar . Her eşleşme gerçekleşmediğinde, sondaki karakter karantinaya alınır ve kontrol tekrar yapılır.

Regex paterninin sadece önde gelen koşulları aktif sekans tarafından karşılandığında, kalan koşulları karantinaya karşı doğrulamak için bir girişimde bulunulur. Bu doğrulama başarılı olursa, karantinadaki eşleşen karakterler doğrulanır ve kalan eşleşmeyen karakterler doğrulanmaz ve bir sonraki yinelemede işlem yeniden başladığında kullanılır.

Karakterlerin akışı aktif sekanstan karantinaya alınır. Ortaya çıkan davranış, orijinal dizinin mümkün olduğunca çoğunun bir eşleşmeye dahil edilmesidir.

İsteksiz Niceleme , karakterlerin akışı zıt olduğu için çoğunlukla açgözlü niteliklerle aynıdır - yani karantinada başlarlar ve aktif diziye akarlar . Sonuçta ortaya çıkan davranış, orijinal dizinin mümkün olduğunca azının bir eşleşmeye dahil edilmesidir.

İyelik Nicemleme bir karantinaya sahip değildir ve her şeyi sabit bir aktif sırayla içerir .

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.