Normal ifadeler gerçekte nasıl çalışır?


30

Diyelim ki yazılı bir yazılı belge var. Bu makaleyi yalnızca belirli sözcükleri seçmek için ayrıştırmak istiyorsunuz. Güzel.

Düzenli bir ifade kullanmak, dosya satırını satır satır, kelime kelimesiyle eşleşmeyi aramaktan daha hızlı mı kullanıyor? Eğer öyleyse, nasıl çalışır? Her kelimeye bakmaktan daha hızlı nasıl gidebilirsin?


5
Normal bir ifadenin daha hızlı olacağını ancak bunun neden olduğunu bilmiyorsunuz (sıfır kanıt ima ederek) varsayıyorsunuz? Belki de varsayımını tekrar gözden geçirmelisin.
pdr

3
Böylece, varsayım. Elimde kanıt olsaydı, bir olmazdı, değil mi?
lazeR

4
Konu o değil. Mesele şu ki, sizi bu varsayıma yönlendiren şey ... Sorularınız için kanıtlara ihtiyacınız yok ama varsayımlarınız için gerekçeye ihtiyacınız var.
yannis

1
Hata, giriş dizesinin her karakteri sadece bir durum makinesini bir sonraki duruma taşıma değil.
Birinin

2
Daha hızlı olduğundan emin değilim, ancak düzenli ifadeler kullanmamın temel nedeni, karmaşık eşleştirme modellerinin zerafetidir, kodlama ortamında eklemlemenin daha iyi bir yolunu bulamazsınız.
Mantorok

Yanıtlar:


47

O nasıl çalışır?

Otomat teorisine bir göz atın

Kısacası, her normal ifadede eşdeğer bir sonlu otomat vardır ve sonlu bir otomat için derlenebilir ve optimize edilebilir. İlgili algoritmalar birçok derleyici kitapta bulunabilir. Bu algoritmalar, awk ve grep gibi unix programları tarafından kullanılır.

Ancak, çoğu modern programlama dili (Perl, Python, Ruby, Java (ve JVM tabanlı diller), C #) bu yaklaşımı kullanmaz. Düzenli bir ifadeyi bir ağaca veya düzenli ifadenin çeşitli alt parçalarını temsil eden yapı dizisine derleyen özyinelemeli bir geri izleme yaklaşımı kullanırlar. En modern "düzenli ifade" sözdizimleri, özyinelemeli geri izleme yaklaşımında önemsiz şekilde uygulanabilir olan normal diller grubunun dışında (sonlu otomata gösterimleri yoktur) geri referanslar sunar.

Optimizasyon genellikle daha verimli bir durum makinesi sağlar. Örneğin: aaaab | aaaac | aaaad'ı düşünün, normal bir programcı on dakika içinde tam olarak basit fakat daha az etkili arama uygulamasını (üç dizgiyi ayrı ayrı karşılaştırarak) alabilir; ancak bunun aaaa [bcd] 'ye eşdeğer olduğunun farkına varmak, ilk dört' a 'aranarak daha iyi bir arama yapılabilir, ardından 5. karakteri [b, c, d]' ye karşı test edin. Optimizasyon süreci, yıllar önce derleyici ev işimden biriydi, bu yüzden bunun en modern düzenli ifade motorlarında da olduğunu varsayarım.

Öte yandan, devlet makineleri, "önemsiz bir uygulama" ile karşılaştırıldığında daha fazla alan kullanmaları nedeniyle, dizeleri kabul ederken bazı avantajlara sahiptir. SQL dizelerinde tırnaktan çıkmak için bir program düşünün, yani: 1) tek tırnak işareti ile başlar ve biter; 2) tek tırnak işareti, iki ardışık tek tırnak işareti ile çıkarılır. Dolayısıyla: ['a' ''] girişi [a '] çıkışını vermelidir. Durum makinesinde, ardışık tek tırnak işaretleri iki durum tarafından ele alınır. Bu iki durum, aşağıdaki şekilde gösterildiği gibi, her giriş karakterinin yalnızca bir kez işleneceği şekilde giriş geçmişini hatırlama amacına hizmet eder:

...
S1->'->S2
S1->*->S1, output *, * can be any other character 
S2->'->S1, output '
S2->*->END, end the current string

Bu nedenle, benim görüşüme göre, düzenli ifade bazı önemsiz durumlarda daha yavaş olabilir, ancak optimizasyonun insan tarafından güvenilir bir şekilde yapılamayacağı gerçeği göz önüne alındığında, genellikle elle hazırlanmış bir arama algoritmasından daha hızlı olabilir.

(Bir dize aramak gibi önemsiz durumlarda bile, bir akıllı motor durum haritasındaki tek yolu tanıyabilir ve bu kısmı basit bir dize karşılaştırmasına indirgeyebilir ve durumları yönetmekten kaçınabilir.)

Bir çerçeveden / kütüphaneden belirli bir motor yavaş olabilir, çünkü motor bir programcının genellikle ihtiyaç duymadığı bir sürü başka şey yapar. Örnek: .NET'teki Regex sınıfı, Eşleştirme, Gruplar ve Yakalamalar da dahil olmak üzere bir sürü nesne oluşturur.


2
Daha iyi söyleyemezdim. Eklemek istiyorum tek şey: Düzenli İfadeler da olabilir makyaj tembel programcılar için. Örnekte Bahsettiğiniz aaaab|aaaac|aaaadVS. aaaa[bcd]. İkisinin matematiksel olarak eşdeğer olduğunu ve aynı DFA'yı ürettiğini açıkça belirtmekte fayda var, bu nedenle programcılara normal bir ifadeyi mantıklı bir şekilde ifade etmeleri için daha fazla özgürlük tanıyorlar (bu yaygın bir uygulama değil, ama, bilirsin). ..
riwalk

Teşekkürler, bu
aldığım

Bu önemsiz bir sorun örneğidir nerede regex is overkill ?: stackoverflow.com/questions/18955099/...
Menelaos Bakopoulos

17

Normal ifadeler sadece hızlı görünüyor çünkü hızlı bilgisayarlarınız var.

1980'lerde, 1 MIPS hızlı bir bilgisayar iken, düzenli ifadeler oldukça büyük bir endişe, endişe ve araştırma alanıydı, çünkü yavaş ve çirkin ve yoğun bir işlem yapıyorlardı. Akıllı algoritma geliştirme izledi ve yardımcı oldu - ancak tüm pratik amaçlar için, bugünlerde hızlı makinelerin çatlaklara kağıt sıkışmasının mucizesini görüyorsunuz.


2
Sadece tek bir kelime arıyorsanız, her iki yöntem de aynıdır (veya regexp biraz daha yavaştır). Ancak karmaşık bir ifade (ve oldukça büyük bir metnin metni) verildiğinde normal ifade muhtemelen basit bir aramadan daha hızlı olacaktır (basit aramayı basitçe yazdığınızı varsayarak (her zaman hızlı olan karmaşık bir arama yazabilirsiniz)). Şimdi hava durumu çok genel bir sorudur ve duruma göre duruma bakmak zorunda kalacaksınız.
Martin York

3
-1. Düzenli ifade teorisi, 50'li yıllara dayanır ve sözlüksel analizörlerin (ve buna göre, derleyicilerin) oluşturulmasında etkili oldu. Mümkün olan en az sayıda devlet kullanan (kanıtlanabilir şekilde) çok verimli durum makineleri yaratırlar. Elde edilen durum makineleri, karmaşık kalıpları, elle yazabileceğiniz her şeyden daha hızlı eşleştirebilir. Hızlı görünüyorlar çünkü hızlılar.
riwalk

Belki de amacımı biraz özledim. "Hızlı" olabilirler ama hepsi göreceli. Bu, yapılacak çok iş var. Buradaki diğer cevapların bazıları da okumaya devam ediyor.
hızla

Bu cevap soru ile alakalı mı? ve nasıl 13 olumlu?
Sadan ve

7

Neden belgeyi aramaktan daha hızlı olduklarını düşünüyorsunuz?

Örneğin yapabileceğiniz bazı püf noktaları vardır. A ile başlayan ve B ile biten bir 10letter kelimesi arıyorsanız, o zaman bir A bulursanız ve 9 pozisyonları daha ileride B ise o zaman bazılarını atlayabilirsiniz. bkz. Knuth – Morris – Pratt algoritması


5

Düzenli bir ifadeyi hızlı yapan nedir?

Aslında değiller. O kadar değil. Sadece çoğumuzun farkına varacak kadar yavaş değiller. 'Eski yavaş günlerde, çok daha dikkat çekiciydi.

Ayrıca her iş için doğru alet değiller - çekiç .


+1 Bana belirli bir sanat yapıtını hatırlattığın için teşekkürler ...
yannis

5

RegEx'ler, yazabildiğiniz kodlara kıyasla nispeten daha hızlıdır , çünkü çoğu kütüphane, birçok geliştiricinin uzun yıllar boyunca mümkün olan her performans bitiminde gıcırtıları için onları optimize etmesinin bir sonucudur. Tek bir bireyin kendi arama kodunda bunu kopyalaması zor.


4
s / squeak / sıkmak /?
Péter Török

4

Temel öncülün yanlış.

Normal ifadeler her zaman basit bir aramadan daha hızlı değildir. Her şey içeriğe bağlı. Bu, ifadenin karmaşıklığına, aranan belgenin uzunluğuna ve bir dizi faktöre bağlıdır.

Olan, normal ifadenin basit bir ayrıştırıcıda derleneceği (zaman alan). Bu nedenle, eğer belge küçükse, bu fazladan zaman herhangi bir avantajdan ağır basacaktır. Ayrıca, ifade basitse, normal ifade size hiçbir avantaj sağlamaz.

İfade karmaşıksa ve belge yeterince büyükse, biraz fayda sağlayabilirsiniz. Bunun normal ifadeleri daha hızlı saymak için yeterince önemli olup olmadığı, aramaya ne kadar çaba harcamak istediğinize bağlı olacaktır (ayrıca normal ifadeler, bir kütüphanenin kendiniz için düşünmeyeceğinize dair sağlayabileceği bazı iyileştirmelere sahip olabilir).

Söylemeye çalıştığım, genelleştirilmiş, battaniye cevabı olmadığı. Belirli bir ifadeye sahipseniz (ve bilinen bir belge boyutuna sahipseniz), ifadenin basit bir aramadan (ve neden) daha hızlı olup olmayacağına dair evet / hayır cevabı türetmişsiniz diyebilirsiniz.

Düzenli ifadelerin asıl avantajı, onları nasıl yazacağınızı anladığınızda, karmaşık bir aramayı özlü bir şekilde ifade etme becerisidir. Genel bir form olduğundan, genel durumda yararlı olacak şekilde arama yapmaya izin veren araçlar oluşturabilirsiniz; genellikle en az basit bir arama kadar hızlıdır (asgari boyuttaki belgeler üzerinde; bundan daha küçük belgeler için önemli olmayacaktır çünkü daha yavaş olsa bile, yeterince hızlıdır).


1

Bazı yüksek seviyeli dillerde (belki javascript), düşük seviyeli bir dilde (belki de C) uygulanan bir regex kitaplığı kullanmak, üst düzey dilde ayrıştırıcı mantık yazmaktan daha hızlı olabilir.

Akla yatkın - Asla durumun böyle olup olmadığı hakkında hiçbir fikrim yok.


Güzel bir! Bu benim de düşündüğüm bir şey. Ancak bugünün işlemcilerinden öncekilerden çok daha hızlı bir şekilde, kodları verimli bir şekilde yazarsanız, diff'e nadiren söyleyebileceğinizi söyleyebilirim. Ben aslında bir bütündeyim, normal ifadenin tamamından daha hızlı bir hipotez üzerinden geçemiyorum! ;-)
user3833732
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.