Düzenli ifade motorunun içini bir kütüphane olarak sunmak
(blog.burntsushi.net)- Rust
regexcrate’i, yıllar süren yeniden yazımın ardından iç motorlarının önemli bir bölümünü ayrı sürümlenenregex-automatacrate API’si olarak yayımladı; geçişregex 1.9ile tamamlandı - Yeniden yazım; arama stratejilerini birleştirme zorluğu, iç motorlara göre test etmenin güçlüğü,
RegexSet’ten daha ayrıntılı çoklu desen API’si ihtiyacı ve tam derlenmiş DFA paylaşma gereksiniminden doğdu regex-automata, düzenli ifade işlemeyiAst → Hir → literal çıkarımı/Prefilter → Thompson NFA → PikeVM·BoundedBacktracker·one-pass DFA·DFA·lazy DFA → meta engineakışıyla kuruyor- Performans, mümkün olduğunda önce literal arama ve DFA ailesi motorları kullanılarak; capture group’lar veya istisnai durumlarda ise
PikeVM·bounded backtracker·one-pass DFA ile tamamlanarak sağlanıyor - Açık API ve yeniden kullanılabilir soyutlamalar test ve deneyi kolaylaştırdı; ancak kod miktarı, ikili dosya boyutu ve derleme süresi arttı. Tam derlenmiş DFA opt-in bırakıldı ve
regex-litehafif bir alternatif olarak eklendi
regex yeniden yazımı ve regex-automatanın yayımlanması
- Rust’ın
regexcrate’i, iç bileşimi iyileştirip optimizasyonları daha kolay eklerken doğruluğu korumak için yıllar boyunca yeniden yazıldı - Bu süreçte
regex-automataoluşturuldu veregexcrate’inin iç uygulamasının önemli bir kısmı ayrı bir API olarak açığa çıkarıldı regex-automata, bir düzenli ifade kütüphanesinin içini bu ölçüde ayrı sürümlenen bir kütüphane olarak yayımlayan ilk örnek olarak tanıtılıyorregex 1.9, 5 Temmuz 2023’te yayımlandı ve bu yeniden yazımı tamamladı- Hedef kitle, Rust programcıları ve sonlu otomat tabanlı düzenli ifade motorlarının uygulanmasıyla ilgilenen kişiler; düzenli ifade deneyimi ön kabul olarak alınıyor
Yeniden yazımdan önceki sorunlar
- Mevcut
regexcrate’i, RE2 geleneğini izleyerek içeride birden fazla arama stratejisi kullanıyordu; ancak stratejiler zamanla organik biçimde eklendikçe birleştirilmesi zorlaştıPikeVM, ilk strateji olarak tasarlandığından lazy DFA ile birleştirildiğinde gereken kısmi slice araması başlatma ve durdurma işlemlerinde eksikti- Hangi düzenli ifadede hangi stratejinin kullanıldığını çıkarsamak zordu
- Birden fazla
matchifadesi aynı mantığı tekrar tekrar uyguluyor, bu da senkronizasyonun kolayca bozulmasına yol açıyordu - Sadece Aho-Corasick yeterli olan düzenli ifadelerde bile kullanılmayacak Thompson NFA gereksiz yere oluşturulabiliyordu
- İç motorları test etmek de zordu
- Açık API tek bir düzenli ifade motoru gibi görünse de içeride birden çok strateji var ve bunların aynı girdide aynı şekilde çalışması gerekiyor
regex 1.9öncesinde iç stratejiler açık API değildi; bu yüzden her motoru bağımsız test etmek zordu- Mevcut testler, iç API açığa çıkarma, belgelenmemiş
Fromimplementasyonları, makrolar ve motor bazlı test hedeflerine dayanan, hack’e yakın bir yapıya sahipti
- Çeşitli niş API taleplerini de mevcut API yüzeyine eklemek zordu
RegexSet, yalnızca hangi desenlerin haystack’in herhangi bir yerinde eşleştiğini bildiriyor; eşleşme ofsetlerini veya capture group ofsetlerini vermiyor- Desene
^eklemeden anchored arama çalıştırma işlevine ihtiyaç vardı - Arama sırasında iç senkronizasyon olmadan mutable scratch space’i doğrudan iletme özelliği talep ediliyordu
- Stream veya rope gibi süreksiz haystack üzerinde düzenli ifade çalıştırma işlevi de istendi
- İç yapının ayrı sürümlenen bir crate olarak açılması, genel amaçlı
regexAPI’sini karmaşıklaştırmadan uzmanlara yönelik API’lerin daha hızlı bir breaking change döngüsüyle denenmesini mümkün kılıyor
Tam derlenmiş DFA’nın oluşturduğu soyutlama sınırı
regex-automatanın ilk motivasyonu, tam derlenmiş bir DFA oluşturup bunu serileştirdikten sonra zero-copy deserileştirme ile arama yapan en küçük çalışma zamanı altyapısını sunmaktı- İlk
regex-automata,bstriçin Unicode algoritmalarını uygulayan DFA’lar üretmekte kullanıldı - DFA oluşturulurken,
regexcrate’ine benzer NFA veri yapıları ve derleyicilere ihtiyaç duyuldu; bu kod karmaşıklaştıkça paylaşım ihtiyacı büyüdü - Başta
regex-nfagibi ayrı bir crate düşünülse de determinization süreci gibi daha fazla kodregexileregex-automataarasında paylaşılabilirdi - Soyutlama sınırı “NFA”dan çok düzenli ifade motoruna yakındı ve sonunda
regex-automatabirden fazla motorun kümesi olarak yeniden tanımlandı - Uzun vadeli plan, tüm düzenli ifade motorlarını
regex-automataiçine koyupregexcrate’ini bunun üzerinde ince bir wrapper’a dönüştürmekti
regex-cli ile iç yapıyı incelemek
regex-cli,regexcrate deposunda yönetilen bir programdır veregex-syntax,regex-automata,regexiçin çeşitli API’lere komut satırından erişim sağlar- Kurulum şu komutla yapılabilir
cargo install regex-cli
regex-cli debug, AST, HIR, literal’lar, Thompson NFA, one-pass DFA, dense DFA, sparse DFA ve benzerlerini çıktıya dökebilir- Unicode açıkken kullanılan
.düzenli ifadesi, UTF-8 scalar value’ları işlemek için çok daha karmaşık bir Thompson NFA üretirken; Unicode kapalı(?-u:.)daha basit bir NFA oluşturur regex-cli find, geçici aramalar çalıştırabilir; ayrıca meta engine ile çoklu desen araması ve capture group çıktısı da verebilir
Düzenli ifade işleme veri akışı
Regex::newiçine verilen desen dizgesi önceAstolarak parse edilirAst, ardındanHirbiçimine dönüştürülürHir,Ast’ye göre daha az ayrıntı içerir; Unicode case folding ve Unicode character class referansları bu dönüşüm sırasında genişletilir
Hir’den iki şey üretilir- Arama optimizasyonunda kullanılan literal dizileri
- Thompson
NFA
- NFA, çeşitli motorları üretmenin temelini oluşturur
PikeVM: parse edilebilen tüm düzenli ifadeleri işler ve capture group ofsetlerini bildirirBoundedBacktracker: bounded backtracking ile capture group ofsetlerini bildirir- one-pass DFA: sınırlı düzenli ifadelerde capture group ofsetlerini hızlıca bildirir
- dense DFA: çok hızlıdır, ancak yalnızca tüm eşleşmenin başlangıç ve bitişini bildirir; oluşturulması en kötü durumda
O(2^m)zaman ve alan gerektirir - lazy DFA: arama sırasında NFA’den DFA oluşturur; genellikle full DFA kadar hızlıdır ve full DFA’nın üstel oluşturma maliyetinden kaçınır
- Bu motorlar ile
Prefilter, tek bir meta regex engine içinde birleştirilir;regexcrate’i de bu meta engine’in ince bir wrapper’ıdır
Literal optimizasyonu
- Literal çıkarımı,
regexiçindeki temel optimizasyonlardan biridir- Örneğin
(foo|bar|quux)(\s+\w+)için tüm eşleşmelerfoo,barveyaquuxile başlar
- Örneğin
- Literal'lerin önemli olmasının nedeni, tek bir veya az sayıda dizge arama algoritmasının çok hızlı olmasıdır
- Vektör komutlarıyla haystack içindeki birden çok bayt aynı anda işlenebilir
- Genel düzenli ifade eşleştirme algoritmalarını aynı şekilde tutarlı biçimde hızlandırmak zordur
- İyi optimize edilmiş substring araması, genel bir düzenli ifade motorundan çoğu zaman en az tek haneli katlar düzeyinde daha hızlı olmuştur
- Literal çıkarımı bir heuristictir
- Aday eşleşmelerin false positive oranını düşürmek gerekir
- Prefilter'ın toplam gecikmeye etkisi de düşük tutulmalıdır
- Her iki koşul da haystack'e bağlıdır, ancak aramadan önce haystack'i analiz etmek toplam arama süresini kötüleştirebilir
- Literal dizisi bir küme değil, sıralı bir dizidir
regexcrate'i Perl benzeri leftmost-first semantiğini izlediği için|için değişme özelliği geçerli değildirsam|samwiseiçin yalnızcasamçıkarılabilirken,samwise|samiçin ikisi de dikkate alınır
- Tek dizge araması için
memchrcrate'ininmemmemmodülü kullanılır- Ana algoritma, en kötü durumda
O(n)zaman ve sabit alan kullanan Two-Way'dir - Kısa needle ve haystack için Rabin-Karp kullanılır
x86_64üzerinde generic SIMD varyantı kullanılır
- Ana algoritma, en kötü durumda
- Çoklu dizge aramasında ana algoritma olarak Hyperscan'den taşınan Teddy kullanılır; bazı durumlarda Aho-Corasick de kullanılır
Thompson NFA ve optimizasyonlar
regexcrate'i içindeki merkezi veri yapısı Thompson NFA'dir- Thompson’s construction, düzenli ifadenin yapılandırılmış gösteriminden
O(m)zamanda bir NFA üretir; buradam, counted repetition genişletildikten sonraki düzenli ifade boyutuyla orantılıdır - NFA doğrudan bir düzenli ifade motoru olarak kullanılabilir ve DFA gibi başka türlere dönüştürülerek diğer motorların temeli de olabilir
- Yeni NFA derleyicisindeki başlıca optimizasyon, epsilon transition sayısını azaltmaya odaklanır
- Thompson NFA'nin kurulum maliyeti iyidir, ancak çok sayıda epsilon transition kullanır
- Epsilon closure hesaplaması, arama veya DFA oluşturma sırasında tekrarlayan bir maliyet yaratabilir
sparsestate optimizasyonu, birden fazla aralık geçişini tek bir durumda ifade ederek mevcut çok sayıdakiSplitinstruction'ı azaltır[A-Za-z0-9]gibi düzenli ifadelerde gereksiz epsilon transition'ları kaldırır- Mevcut gösterimde indirection nedeniyle cache etkisi ve heap memory artışı ihtimali vardır
- Minimal UTF-8 automata optimizasyonu, büyük Unicode class'larda NFA boyutunu önemli ölçüde küçültür
- Eski byte-oriented NFA'de
\w, 3.564 state oluşturabiliyordu - Yeni derleyici, Daciuk’s algorithm kullanarak çok daha az state ve sıfır epsilon transition içeren bir yapı oluşturur
- Reverse NFA'nin küçültülmesi, compile time maliyeti nedeniyle varsayılan olarak devre dışıdır
- Eski byte-oriented NFA'de
- Literal trie optimizasyonu,
zap|z|zapper,abc|xyzgibi literal alternation'larda ortak yapıyı trie olarak derleyip epsilon transition'ları azaltır- Leftmost-first semantiğini korumak için eşleşmenin göründüğü her noktada transition chunk'ları bölünür
- Gelecekteki NFA çalışmaları arasında Glushkov NFA ve tek bir contiguous allocation içinde depolama değerlendirilmektedir
- Glushkov NFA'de epsilon transition yoktur, ancak compile time karmaşıklığı daha kötüdür
- Contiguous allocation, cache dostu yapı ve zero-copy serileştirme/deserialize etme imkânı sunabilir; ancak kod karmaşıklığı ve
unsafekullanımı ihtimali vardır
Ayrı düzenli ifade motorları
regex-automatamotorları benzer API'leri paylaşırInput: haystack, arama aralığı, anchored olup olmadığı ve early stop ayarlanırMatch: eşleşen byte span'ini vePatternIDiçerirMatchError: arama sonucunun belirlenemediği hataları gösterir
-
PikeVM
regex-syntaxtarafından ayrıştırılabilen tüm özellikleri destekler ve her uzunluktaki haystack üzerinde çalışır- Capture group konumlarını izler ve etkin state'leri lock-step olarak hesaplayarak en kötü durumda
O(m * n)zamanı garanti eder - Çok sayıda state ve capture group konumunun izlenmesi gerektiğinden performans temel zayıf noktasıdır
regex-automatamotorları arasında, arama sırasında hata döndürmeyen tek motordur
-
BoundedBacktracker
- Thompson NFA üzerinde backtracking kullanır, ancak daha önce yapılan işi yeniden izlememek için ek state kullanır
- En kötü durumda
O(m * n)zamanı garanti eder, ancakO(m * n)alan kullanır - Kabaca yapılan deneylerde genellikle
PikeVM'den yaklaşık 2 kat daha hızlıdır - Haystack uzunluğu ve düzenli ifade boyutu, ayarlanan visited capacity'yi aşarsa başarısız olabilir
-
one-pass DFA
- Kısıtlı bir one-pass NFA üzerinde capture group offset'lerini çok hızlı raporlar
- Capture group'ları raporlamanın en hızlı yolu olarak görülür
- Yalnızca anchored search desteklenir ve birçok düzenli ifade one-pass değildir
- Unicode modunda byte düzeyi transition çakışmaları nedeniyle one-pass olmayan bir düzenli ifade, Unicode kapatıldığında one-pass olabilir
-
fully compiled DFA
- Bir eşleşmenin sonunu ve başlangıcını bulmak için bir forward DFA ve bir reverse DFA'den oluşur
- Oluşturma en kötü durumda
O(2^m)zaman ve alan gerektirir; dense DFA ise çok bellek kullanır - Full DFA motoru,
regexcrate'inde varsayılan olarak devre dışıdır;perf-dfa-fullfeature'ı ile isteğe bağlı olarak etkinleştirilmelidir - Değiştirilebilir bir
Cacheolmadan çalışır ve ham baytlara serileştirilerek yalnızcacorebulunan ortamlarda da arama çalışma zamanı kullanılabilir
-
hybrid NFA/DFA, lazy DFA
- Full DFA'ye benzer, ancak transition table'ı arama sırasında oluşturur
- Cache'te önceden hesaplanmış bir transition varsa yeniden kullanır; yoksa NFA powerset construction ile yalnızca ilgili transition'ı hesaplar
- En kötü arama süresi
O(m * n), alan kullanımı ise oluşturma sırasında belirlenen cache capacity ile sınırlıdır - Genel durumda state ve transition'ların çoğu cache'lendiği için ortalamada
O(n)gibi çalışır ve pratikte birçok düzenli ifadede full DFA'ye benzer arama performansı gösterir - Cache tekrar tekrar dolup verimsiz hâle gelirse hata döndürür; meta engine içinde ise genellikle başka bir motorla yeniden denenir
meta regex enginein rolü
meta regex engine, birden çok motoru tek bir yapıda birleştirir ve çağırana hatasız bir API sunmayı amaçlar- Çağıranın her arama için doğrudan
Cacheoluşturup geçirmesi gerekmez- meta engine, dahili thread-safe bir cache havuzunu yönetir
- senkronizasyon maliyetinden kaçınmak istenirse, açıkça
Cachegeçirilen daha alt seviye bir API de sunulur
regex::Regex,regex::RegexSet,regex::bytes::Regex,regex::bytes::RegexSetyapılarının tümü meta engine için ince birer sarmalayıcıdır- meta engine'in dahili stratejisi kabaca şöyledir
- Regex motoru olmadan yalnızca tekli veya çoklu substring aramasıyla çözülebiliyorsa NFA kurulumundan da kaçınır
- Mümkünse prefix literal dizilerini çıkarıp bunları
Prefilterolarak kullanır - Prefix uygun değilse reverse anchored, reverse suffix ve reverse inner optimizasyonlarını dener
- Bunların dışında
PikeVM, bounded backtracker, one-pass DFA, lazy DFA ve full DFA içeren çekirdek stratejiye geri düşer
- Genel strateji iki cümlede özetlenebilir
- Mümkün olduğunca literal ara
- Mümkün olduğunca
PikeVMkullanımından kaçın
- reverse suffix ve reverse inner optimizasyonları yanlış uygulanırsa haystack boyutu için en kötü durumda
O(m * n^2)olabilir- meta engine, reverse scan'in önceki suffix eşleşmesinin sonunu aşmaya çalıştığı durumu tespit eder ve zaman karmaşıklığı garantisini korumak için çekirdek stratejiye geri döner
RE2 ile farklar
regexcrate'i ile RE2 arasında birçok benzerlik vardır- RE2'de de
PikeVMkarşılığı bir NFA, bitstate backtracker, one-pass NFA, lazy DFA ve birden çok motoru birleştiren bir yapı bulunur - Yukarıdaki motorlar arasında RE2'de olmayan tek şey fully compiled DFA'dır
- RE2'de de
- Başlıca farklar şunlardır
- RE2, leftmost-first'e ek olarak POSIX tarzı leftmost-longest anlambilimini de isteğe bağlı olarak destekler
- RE2'nin Unicode desteği daha sınırlıdır ve
\w,\s,\d,\biçin Unicode tanımlarını kullanma seçeneği yoktur - RE2, character class set operation işlemlerinde union dışındaki destek konusunda sınırlıdır
- RE2'nin
PikeVMuygulaması bellek açısından daha verimli olabilir - RE2'nin literal optimizasyonları sınırlıdır;
regexcrate'i daha fazla literal optimizasyonu yapar - RE2 lazy DFA'sında birden çok thread aynı transition cache'i paylaşır, bu yüzden senkronizasyon gerekir;
regexcrate'i ise thread başına ayrı cache ister ve bu nedenle daha fazla bellek kullanır regexcrate'i,regex-syntaxveregex-automatayı ayrı sürümlenen kütüphaneler olarak yayımlar, RE2 ise bunu desteklemezregex-automata, tüm motorlarda birinci sınıf multi-pattern regex desteği sunar ve eşleşen her pattern için match ile capture group offset'lerini de raporlayabilir
Test stratejisi ve benchmark'lar
- Yeni test stratejisi, dahili motorları bağımsız birer birinci sınıf API haline getirip her motoru doğrudan test etmeye dayanır
- Tüm regex testleri TOML dosyalarıyla tanımlanır
regex-testcrate'i, TOML testlerini okuyup yapılandırılmış bir gösterime dönüştürür- Her motor yapılandırması için bir Rust unit test'i bulunur ve o motora uygulanabilen tüm TOML testleri çalıştırılır
- Rust unit test çerçevesi genişletilebilir olmadığından, belirli testleri filtrelemek için özel environment variable altyapısı eklenmiştir
- Yalnızca
regex-automataiçinde 450'den fazla documentation test bulunur regex 1.9hazırlıkları sırasında çok sayıda fuzz testing hedefi de eklendi ve Addison Crump'ın yardımıyla birkaç hata bulundu- Benchmark'lar,
rebaradlı regex barometer ile yayımlanırrebar, yalnızcaregexcrate'ini değil, çeşitli regex motorlarını da benchmark eder- 242 benchmark'ta
regex 1.9, arama süresi açısındanregex 1.7.3e göre ortalama 1,5 kat daha hızlıdır - Regex derleme süresi ise bir miktar gerilemiştir
1.8, bazı geçiş çalışmalarını içeren bir transition release olduğundan karşılaştırma temeli olarak1.7kullanılmıştır
Maliyet ve hafif alternatifler
- Yeniden yazım için son birkaç yılda yazarın boş zamanının büyük kısmı harcandı ve ripgrep gibi projeler bir süre yayımlanamadı
- Yeniden kullanılabilir kamuya açık soyutlamalar, yalnızca dahili kullanıma yönelik soyutlamalara göre daha fazla kod gerektirme eğilimindedir
- Bunun sonucunda binary boyutu ve derleme süresi artar
- Dahili motor API'si ayrı sürümlenen şekilde yayımlandığından, API'yi bozmak için
regex-automatatarafında uygun bir breaking change release gerekir - Maliyeti hafifletmek için iki önlem uygulanmıştır
- fully compiled DFA motoru varsayılan olarak devre dışıdır ve isteğe bağlı bir feature olarak bırakılmıştır
regex-liteyeni bir crate olarak yayımlanmıştır
regex-lite,regexcrate'inin neredeyse drop-in replacement'ı olmayı hedefler; ancak odağı binary boyutu ve derleme süresini optimize etmektir- Unicode ve performans tarafındaki bazı özelliklerden vazgeçer
O(m * n)zaman karmaşıklığı garantisini korur- Hiç bağımlılığı yoktur, kendi regex parser'ını içerir ve
regexcrate'iyle kod paylaşmaz
regex-liteşimdilik deneysel bir hafifletme yöntemi olsa da,regexcrate'inde feature'lar üzerinden optimizasyon ve Unicode işlevleri kapatılsa bile binary boyutu ve derleme süresinderegex-liteseviyesine yaklaşmanın zor olduğunu gösterir
1 yorum
Hacker News yorumları
Sadece kabaca göz atmış olsam da Rust regex crate gerçekten çok etkileyici
BurntSushi'nin yaptığı harika işler çok ama Rust'ın regex crate'i efsanevi; Rust ekosisteminin uzun zamandır performanslı ve kullanımı kolay bir düzenli ifade kütüphanesine sahip olması topluluk için büyük bir nimet
Russ Cox'un düzenli ifadeler üzerine yazı dizisi de harika; düzenli ifadeler teoriyle pratiğin kusursuz kesişim noktası gibi gelmeye başladığında yaz boyunca bir düzenli ifade motoru yaparken ona başvurmuştum
Bu yazıdaki daha derin test değişiklikleri de ilginç ve ekosistem için çekirdek bir crate olduğu düşünülürse bu kadar derin konuların açıklanması takdire değer
Düzenli ifadeler bazen okunması zor olabilir ve e-posta doğrulama gibi yerlerde fazla kullanılabilir ama neredeyse her dilde en yoğun araçlardan biridir
Pratik tarafta Jeffrey Friedl'in Mastering Regular Expressions kitabını iyi biliyorum; teori tarafınıysa derleyici kitapları ele alıyor ve Dragon Book da uygulama perspektifinden fena değildi. Başka düzenli ifade kitabı önerilerini merak ediyorum
Yaklaşım, düzenli ifade için bir deterministik olmayan sonlu otomat kurup ortaya çıkan yönlü grafikte arama yapmak ve son durumlara karşılık gelen düğümlere ulaşılabiliyorsa bunu eşleşme saymak
Düzenli ifade kullanan biri için bu alıştırma işin sanıldığından daha az sihirli olduğunu anlamaya yardımcı oluyor; NFA üzerinde sekip duran topları hayal edince üretimde eninde sonunda karşınıza çıkan felaket düzeyinde backtracking hataları da fiziksel bir anlam kazanıyor
Asıl yazıyla ilgili olarak, https://github.com/rust-lang/regex/issues/822 içindeki son BurntSushi yorumu, niş API paragrafına https://blog.burntsushi.net/regex-internals/#problem-request... faydalı bir bağlam ekliyor. Birden fazla düzenli ifadeyi metin üzerinde aynı anda aramak çok karmaşık ama çok faydalı; topluluğun bu kalıpla neler inşa edeceğini merakla bekliyorum
Örneğin
header:field1,field2,field3"data"hashgibi alan sayısı sabit biçimlerde ya dasuite~split/test1,test2@opt1:opt2^hw1^hw2#flags1#flags2gibi öğelerin çoğunun isteğe bağlı olduğu biçimlerdesplitgibi temel araçlar yetersiz kalır ve düzenli ifadeler iyi otururDüzenli ifadelerin neden hızla okunamaz hâle geldiğinin sebebi de budur. Tek bir düzenli ifadeye alanlar arası ayraçlar, her alanın geçerliliği ve hangi alanların isteğe bağlı olduğu birden yüklenir
Oysa bunlar aslında üç ayrı ilgidir ama çoğu regex API'si bunları aşamalı olarak ayırmaya izin vermez, her şeyi birleştiren tek bir string vermenizi ister
Dil kısıtları ve telif hakkı koruması nedeniyle RegEx işlevini doğrudan yeniden yapmak zorunda kaldım ve düzenli ifadeler gerçekten bazen büyü gibi hissettiriyor
Diğer motorların ne kadar sık kullanıldığını bilmiyorum ama pek çok programlama dili PikeVM kullanıyorsa, Google'ın sunucuları için kendi işletim sistemini yapıp belirli durumlarda daha hızlı motorları devreye sokarak birkaç clock cycle bile kazanmaya çalışmasını anlayabiliyorum
Arama string'ine birkaç karakter eklemenin bile pattern matching'i ciddi biçimde yavaşlatabildiğini gayet iyi biliyorum. “Damlaya damlaya göl olur” sözü RegEx ve clock cycle için de çok uygun; saniyede milyonlarca kaydın işlendiği 90'lar sohbetlerine bakınca bunun bazı kodlayıcıları epey zengin etmiş olabileceğini düşünmeden edemiyorum
Özellikle lehçeye ve bağlama göre tırnak işleme ya da ifadenin nasıl sonlandığı o kadar değişiyor ki ezberlemeye çalışmayı bıraktım; ihtiyaç oldukça örnek arıyorum
ActiveState'de okuldan yeni mezun olmuş bir çalışma arkadaşımla birlikte Komodo editörü için bir düzenli ifade hata ayıklayıcısı yapma görevi almıştım
Efsanevi Perl uzmanı Mark Jason Dominus'u işe alıp Perl düzenli ifade motoruna hook'lar eklettik ve bu hook'ları UI'da görünür kılarak kullanıcının düzenli ifade çalışmasını adım adım izlemesini sağladık
Bugünlerde web tabanlı araçlar daha iyi olsa da 2001'de Komodo'nun Rx Debugger'ı son teknoloji sayılırdı ve üzerinde çalışması da çok eğlenceliydi
Air-gap ağlarla çalışıyordum; bu yüzden araçları kullanması gereken kişiler çevrimiçi sitelere erişemiyordu ve hangi tasarım olursa olsun iş verilerini çevrimiçi araçlara koymak düşünülemezdi
Ama çabaların çoğu çevrimiçi araçlara gidiyor; çevrimdışı araçlar ise https://regex101.com/ gibi şeylerle karşılaştırıldığında nadir ve yetersiz kalıyor
Bunun string olmayan listelerde de kullanılıp kullanılamayacağını merak ediyorum
Karakter listelerini arayıp değiştirmek için güçlü araçlar var ama konu sayı ya da tarih listelerine gelince hepsinin bir anda ortadan kaybolması hep can sıkıcı gelmiştir
Örneğin giriş denemesi tarihleri listesindeki, 5 veya daha fazla başarısız denemenin ardından başarı gelen tüm dizileri bulmak istesem, regex ile bu basit olurdu; ama pratikte elle döngü, bayraklar ve geçici listeler kurmak gerekiyor
Listeleri string'e çevirip işledikten sonra geri dönüştürmek de mümkün, ama bunun dezavantajları açık. String tabanlı regex kadar hızlı olmasa bile, rastgele liste türleri için bir regex neden olmasın anlamıyorum
Eskiden yaptığım Python prototipini de buldum: https://github.com/boppreh/listregex
Çok yavaş ama API deneyi olarak tatmin edici ve desen tersleme, kesişim, eşleştirme gibi regex'te olmayan araçlar da sunuyor
Böyle bir regex motoruna jenerik bir alfabe kazandırmak en baştan gerçekçi değil. Özellikle de API tasarımına ve ana kullanım senaryolarındaki performansa zarar vermeden bunu yapmak pratikte fazlasıyla zor
Performansı önemsemeyen böyle bir regex motoru yapmak zor değil. Örneğin yayımladığım
regex-litecrate'ini alıp istediğiniz kadar jenerik hale getirebilirsiniz; bu süreçte de ilginç zorluklarla karşılaşırsınızBöyle şeyler tamamen yok değil. İnsanlar bunu yapmaya çalışıyor[1]. Ancak genel faydasını biraz abarttıkları için genelde büyük traction elde edemiyor gibi görünüyor :-)
[1]: https://docs.rs/automata/latest/automata/trait.Alphabet.html
std::basic_regex, kullanıcı tanımlı karakter tipleri için bir şablon sınıfı sunarak bunu deniyor: https://en.cppreference.com/w/cpp/regex/basic_regexKullanıcı tanımlı “karakter” için gerekli davranışları tanımlayan trait sınıfları sağlayabiliyorsunuz
Ama performans ciddi biçimde düşüyor ve bu yaklaşım muhtemelen karakter olmayan rastgele nesneleri kullanıcı tanımlı bir
std::basic_stringiçine koymak kadar iyi çalışıyorİmkansız değil ama çoğu dil bunun için iyi bir arayüz sunmuyor
Kodda ya da metin dosyalarında bir şey ararken Ripgrep'i her gün kullanıyorum; Windows, Linux, Mac, VSCode, Vim fark etmeksizin her kullandığımda minnet duyuyorum
Hayatımı ve çalışma biçimimi değiştiren yazılımlardan biri
Zorla
grepkullanmak zorunda kaldığımda, her şeyin tek çekirdekli CPU'da çalıştığı ve verilerin yavaş PATA/IDE döner disklerde bulunduğu döneme geri dönmüşüm gibi geliyorBurntSushi, büyük programcılar arasında fazlasıyla saygıyı hak ediyor
ag, ondan önce deackvardı ve hepsi basitgrepten çok daha iyi bir arayüz sunmaya çalışıyorduİşle ilgili bir problem yüzünden 10 milyondan fazla çok uzun regex ile bir
RegexSetoluşturmam gerektiHiçbir motor varsayılan ayarlarla bununla başa çıkamadı; Rust'ın
RegexSeti de varsayılan haliyle yeterli değildiYine de
regex-automataveregex-syntaxkullanmak ve kodu okumak, 2018'de bile çok faydalı bir öğrenme kaynağıydıSonunda iş projesi Lucene API'sini model aldı ama bunu yapabilmemin temeli regex crate'lerinden öğrendiklerimdi
Bundan sonraki iş, regex motorlarını daha fazla desenle daha iyi ölçeklenecek hale getirmek. Şu anda 10 milyon regex'e gelmeden çok önce çökerdi ve bu hedefin gerçekten mümkün olup olmadığından bile emin olmak zor
Yine de bugünkünden daha iyi olabilir
Elbette çoklu desen aramada Hyperscan fiilen altın standart. Ama 10 milyon deseni ne kadar iyi işler, bilmiyorum
Eskiden
regex-automatacrate'iyle denemeler yapmıştım; iç DFA'ya doğrudan erişim verdiği için bir metin editöründe kullanabildiğim tek kütüphaneydiTipik regex kütüphanesi API'leri girdinin tek ve kesintisiz bir string olduğunu varsayar, ama bu yaklaşım herhangi bir metin veri yapısıyla uyumlu
regex-automatacrate'inin kodunu, üstelik ilk0.2.0sürümünü kullanan kod yazarken bu yazı çıktıGörünüşe göre yeni iç yapıyı yeniden inceleme zamanı gelmiş
Yazıyı henüz okumadım ama çok ilginç ve zamanlaması da kusursuz bir yazı gibi görünüyor
Birkaç dakika sonra bakınca cevap “olabilir”e daha yakındı, ama resmi sürüm olduğu için kodu ciddi ölçüde sadeleştirebileceğim gibi duruyordu
Bir 10 dakika daha sonra geçiş oldukça painless oldu ve yeni
Builder::patchmetodu tam bir yükseltmeydiNot olarak, hâlâ tüm GitHub depolarınızda engelliyim; pek çok crate'in yaygın kullanıldığı düşünülürse bu biraz haksız geliyor. Asıl olayı hatırlamıyorum. regex crate'lerinin kendisi artık
rust-langorganizasyonu altında gibi görünüyor ama yine de etkileşime giremediğim şeyler varregex-automata0.2.0belgelerinde bununla ilgili büyük bir uyarı vardı ve0.1kullanılması şiddetle tavsiye ediliyordu: https://docs.rs/regex-automata/0.2.0/regex_automata/Ben de asıl olayı hatırlamıyorum. Çeşitli nedenlerle birçok kişiyi engelliyorum ama şimdi engeli kaldırdım
BioJulia, derleme zamanında rastgele Julia kodu ekleyebilen saf Julia regex motoru Automa.jl'yi yayımladı
Rust'un regex'inin Automa'dan çok daha gelişmiş olduğu gerçeğini küçümsemek istemiyorum, ancak regex'in iç yapısını bir kütüphane olarak dışa açan ilk örnek olduğu ifadesine katılmak zor
Örneğin PCRE2'de, söylenene benzer gelen “callout” desteği var: https://www.pcre.org/current/doc/html/pcre2callout.html
ragelvere2cgibi araçlar da benzer şeyler yapıyorduBu blog yazısında kastedilen, regex kütüphanesinin kendi iç yapısını çıkarıp ayrı sürümlenen bir kütüphane haline getirmek ve başkalarının bunları birleştirebilmesini sağlamak
Backtracking yapanlarda genelde yalnızca tek bir backtracker motoru olduğu için bu yaklaşım daha az doğal, ancak otomaton tabanlı kütüphaneler çoğu zaman birden fazla motoru çeşitli şekillerde birleştiriyor
Yine de backtracking yapanlar da pratikte dışa açılmayan regex ayrıştırıcısı veya AST gibi şeyleri dışa açabilir