Sonlu durumlu otomatlarda geri referansları, görünüşleri ve görünüşleri nasıl simüle edebilirim?


26

Düzenli bir ifade alıp ayrıştırma ağacını oluşturmak için basit bir düzenli ifade yazıcısı ve ayrıştırıcı oluşturdum. Bu ayrıştırma ağacından deterministik olmayan bir sonlu durum otomatı oluşturmak, temel normal ifadeler için nispeten basittir. Bununla birlikte, kafamı geriye dönüşleri, bakışları ve bakışları nasıl simüle edebileceğimin etrafına saramıyorum.

Ben mor ejderha kitapta okuduklarım itibaren ben bir lookahead simüle etmek anlaşılmaktadır düzenli ifade nereye maç düzenli ifade bir maç izler yalnızca ve eğer eşleştirilir , olmayan bir deterministik sonlu örgü oluşturmak içinde olan ile değiştirilen durum otomatiği . Aynısını yapan deterministik bir sonlu durum otomatı oluşturmak mümkün müdür?r s / εr/srs/ε

Negatif bakış açıları ve bakış açıları benzetmeye ne dersiniz? Beni bunun nasıl detaylı bir şekilde yapılacağını açıklayan bir kaynağa bağlarsanız çok sevinirim.



Yanıtlar:


21

Her şeyden önce, geribaşvurularla olabilir değil onlar olmayan düzenli dilleri tanımlamak için izin verdiği sonlu otomata tarafından simüle edilebilir. Örneğin,([ab]^*)\1 eşleşir , bu bağlam bağlamında bile değildir.{www{a,b}}

İleriye bakmak ve geriye bakmak, sonlu otomata dünyasında özel bir şey değildir, çünkü biz sadece tüm girdilerle eşleşiriz. Bu nedenle, "sadece kontrol et ama tüketme" nin özel anlamı anlamsızdır; sadece ifadeleri kontrol etmeyi ve tüketmeyi kesiyor ve / veya sonuçta elde edilen otomatik verileri kullanıyorsunuz. Buradaki fikir, girişi "tüketirken" ve sonucu bir durumda saklarken ileriye dönük veya geriye dönük ifadeleri kontrol etmektir.

Regexps uygularken, girişi bir otomat ile çalıştırmak ve eşleşme başlangıç ​​ve bitiş indekslerini geri almak istiyorsunuz. Bu çok farklı bir iştir, bu nedenle sonlu otomatlar için bir yapı yoktur. Otomatonunuzu, ileriye dönük veya geriye dönük ifadenin tükeniyormuş gibi oluşturuyorsunuz ve dizin saklama yanıtınızı değiştiriyorsunuz. buna göre raporlama.

Mesela, seyircileri alın. Kontrol regexp'sini eşzamanlı tüketen "all-all" regexp ile eşzamanlı olarak uygulayarak regexp anlamını taklit edebiliriz. sadece geriye dönük ifadenin otomatiğinin son durumda olduğu durumlardan korunan ifadenin otomatiği girilebilir. Örneğin, regexp /(?=c)[ab]+/( 'in tam alfabesi olduğunu varsayarsak ) - bunun normal ifadesine çevrildiğine dikkat edin - ile eşleştirilebilir{ a , b , c } c { a , b } + { a , b , c } {a,b,c}{a,b,c}c{a,b}+{a,b,c}

görüntü tanımını buraya girin
[ kaynak ]

ve zorundasın

  • girdiğinizde geçerli dizini olarak (başlangıçta veya ) veq 2 q 2iq2q2
  • Bir (maksimum) maçı rapor akım indeksi (için sen (terk et) vurduğuz) .- 1 q 2i1q2

Otomattonun sol kısmının, kanonik otomatların paralel otomatlarını , sırasıyla [abc]*ve c(yinelemeli) olduğuna dikkat edin .

Bakış açıları benzer şekilde ele alınabilir; “ana” otomatize girdiğinizde indeksini , ana otomatdan çıkıp öndeki otomatiğe girdiğinizde indisini hatırlamanız ve sadece öndeki otomatın finaline girdiğinizde ile arasındaki bir eşleşmeyi bildirmeniz gerekir. belirtmek, bildirmek.j ben jijij

Belirsizlik yapmamanın buna özgü olduğuna dikkat edin: ana ve ileriye bakma / gözüken otomatizasyonu üst üste gelebilir, bu nedenle eşleşenleri daha sonra bildirmek veya geri izlemek için aralarındaki tüm geçişleri saklamanız gerekir.


11

Regex motorlarını uygulamanın arkasındaki pragmatik konulardaki yetkili referans, Russ Cox'un üç blog yazısından oluşan bir seridir . Burada açıklandığı gibi, geri referanslar dilinizi düzenli yapmadığından, geri izleme kullanılarak uygulanırlar .

Regex desen eşleştirme motorlarının birçok özelliği gibi, lookaheads ve lookbehinds, bir dize bir dilin bir üyesi olup olmadığına karar verme paradigmasına pek uymuyor. Regex'ler yerine genellikle daha büyük bir dizgede alt dizgileri arıyoruz. "Eşleşmeler", dilin üyeleri olan alt dizelerdir ve dönüş değeri, alt dizenin daha büyük dize içindeki başlangıç ​​ve bitiş noktalarıdır.

Bakış açılarının ve bakış açılarının noktası, normal olmayan dilleri eşleştirme yeteneğini ortaya koymak için çok değil, motorun eşleşen alt tablonun başlangıç ​​ve bitiş noktalarını rapor ettiği yeri ayarlamaktır.

Http://www.regular-expressions.info/lookaround.html adresindeki açıklamaya güveniyorum . Bu özelliği destekleyen regex motorları (Perl, TCL, Python, Ruby, ...) hepsi geri izlemeye dayanıyor gibi görünmektedir (yani, normal dillerden çok daha büyük bir dil grubunu desteklemektedir). Bu özelliği, görevi gerçekleştirmek için gerçek sonlu otomatlar oluşturmaya çalışmak yerine, geri izlemenin nispeten "basit" bir uzantısı olarak uyguluyorlar.

Olumlu Bakış

Sözdizimi pozitif lookahead olduğunu (?=regex) . Yani, örneğin q(?=u)maçları qbunun ardından yalnızca u, ama uymuyor u. Bunu, geri izleme üzerinde bir değişiklikle uyguladıklarını hayal ediyorum. Pozitif görünümden önceki ifade için bir FSM oluşturun. Bu eşleşmeler nerede bittiğini hatırlayın ve pozitif görünüm içindeki ifadeyi temsil eden yeni bir FSM'yi başlatın. Eğer bu eşleşirse, o zaman bir "eşleşme" ye sahip olursunuz, fakat eşleşme "pozitif" görünüş eşleşmesinin başladığı pozisyondan hemen önce biter.

Bunun geri izlemeden zor olacak olan tek kısmı, bakışın başladığı girişteki noktayı hatırlamanız ve eşleştirme işlemini tamamladıktan sonra giriş bandınızı bu konuma geri getirmeniz gerektiğidir.

Olumsuz Bakış

Sözdizimi negatif lookahead olduğunu (?!regex) . Dolayısıyla, örneğin sadece takip etmiyorsa q(?!u)eşleşir . Bu, ya başka bir karakter tarafından takip edilebilir ya da dizenin en sonundaki bir olabilir. Bunun, lookahead ifadesi için bir NFA oluşturarak, ardından sadece NFA'nın sonraki dizgiyi eşleştirememesi durumunda başarılı olacağını düşünüyorum.quqq

Eğer geriye dönüşe güvenmeden yapmak istiyorsanız, lookahead ifadesinin NFA'sını ihmal edebilirsiniz, o zaman ona pozitif lookahead ile aynı şekilde davranın.

Olumlu Lookbehind

Sözdizimi Pozitif Geriye İlerleme olduğunu (?<=regex) . Bu nedenle, örneğin, (?=q)ueşleşir u, ancak yalnızca ondan önce gelirse q, eşleşmezse q. Görünüşe göre bu, regex motorunun gerçekte karakterlerini yedeklediği ve regex'i bu karakterleriyle eşleştirmeye çalıştığı tam bir hack olarak uygulanmaktadır . Bu, regex'in yalnızca uzunluğu ile aynı olacak şekilde olması gerektiği anlamına gelir .n nnnn

Bunu, regex ile biten "string" in kesişimini , lookbehind operatöründen önce gelen regex'in hangi kısmıyla olursa olsun alarak tekrar izlemeden uygulayabilirsiniz. Bu Geriye dönük çünkü zor olsa olacak regex girişinin cari başından daha ileriye geri bakmak gerekebilir.

Olumsuz Bakış

Sözdizimi Negatif Geriye İlerleme olduğunu (?<!regex) . Dolayısıyla, örneğin (?<!q)ueşleşir u, ancak bundan önce gelmemişse q. O eşleşir Yani uiçinde umbrellave uiçinde doubtdeğil ude quick. Yine, bu, regex'in uzunluğunu hesaplayarak, birçok karakteri yedekleyerek, regex ile eşleşmeyi test ederek , ancak gözbebeki eşleşirse tüm eşleşmeyi kaldırarak yapılıyor gibi görünüyor.

Sen inkarını alarak geriye olmadan bu uygulamaya mümkün olabilir regex ve Pozitif Geriye İlerleme için yapacağı gibi daha sonra aynı şeyi.


5

En azından geri referanslar için bu mümkün değil. Örneğin, regex (.*)\1normal olmayan bir dili temsil eder. Bunun anlamı, bu dili tanıyan sonlu bir otomat (belirleyici veya değil) yaratmanın imkansız olmasıdır. Bunu resmi olarak kanıtlamak istiyorsanız , pompalama lemasını kullanabilirsiniz .


4

Bu konuyu kendim araştırıyorum ve Alternatif Sonlu Otomatlar kullanarak bakış açısını uygulayabilmelisiniz . Bakışla karşılaştığınızda, yalnızca bakış açısını ve ifadenin kalanını sıradan bir şekilde çalıştırmazsınız, yalnızca her iki yol da kabul ederse kabul eder. Bir AFA'yı makul bir patlamaya (ve dolayısıyla bir DFA'ya) sahip bir NFA'ya dönüştürebilirsiniz, ancak bariz yapının yakalama gruplarıyla iyi oynadığını doğrulamamıştım.

Sabit genişlikteki göz bandı geri izleme olmadan mükemmel bir şekilde mümkün olmalıdır. Let , n genişliğinin. NFA'nızdaki gözbebekinin başladığı noktadan başlayarak, geriye doğru bakarken durumları ayırırsınız, böylece gözbütçesine giden her yol sadece gözbebekine giren devletlerin değerine sahip n karakteriyle sona erer . Ardından, bu durumların başlangıcına bir bakış ekleyin (ve istenirse derhal AFA'dan NFA'ya kadar olan alt yazıyı derleyin).

Geri referanslar, diğerlerinin belirttiği gibi, düzenli değildir, bu nedenle sonlu bir otomat tarafından uygulanamazlar. Aslında, bunlar NP tamamlandı. Üzerinde çalıştığım uygulamada, hızlı evet / hayır eşleşmesi çok önemlidir, bu nedenle geri referansları hiç uygulamamayı seçtim.

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.