Düzenli ifadelerde $ her zaman “dizgenin sonu” değildir
(sethmlarson.dev)- Python
reiçindeki$, çok satırlı mod kapalı olsa bile yalnızca dizgenin sonu ile değil, sondaki son satır sonu karakterinden önceki konum ile de eşleşebilir ^“dizgenin başlangıcı” gibi görünüyor diye$’ın da tamamen simetrik çalıştığını varsaymamak gerekir; gerçek anlamı düzenli ifade gerçeklemelerine göre değişir"cat\n"için$,\z,\Zsonuçları PHP, ECMAScript, Python, Go, Java 8, .NET 7.0 ve Rust arasında farklıdır; Python’daki\zise Python 3.14 ile yeni eklenmiştir- Sondaki satır sonu karakterine izin veriliyorsa, çok satırlı moddaki
$tabloda yer alan tüm platformlarda"cat\n"ile eşleşir; ancak satır sonu hariç son ile eşleşmek isteniyorsa sözdizimi seçimi değişir - Son satır sonu karakteriyle eşleşmemesi gerekiyorsa çoğu platformda
\zkullanılmalı; Python 3.14 öncesinde ve ECMAScript’te ise ayrı alternatifler düşünülmelidir
Python re içinde $’ın eşleştiği konum
- Python düzenli ifade modülü
reiçinde$, çok satırlı mod kapalı olsa bile dizgenin sonu ya da dizge sonundaki son satır sonu karakterinin hemen öncesiyle eşleşebilir cat$,"lolcat"ile eşleşir ve"internet cat video"ile eşleşmez; bu yüzden basit görünür, ancak sonda satır sonu bulunan"cat\n"gibi durumlarda sonuç beklenenden farklı olabilirre.MULTILINEbelirtildiğinde$, dizgenin sonu ve her satırın sonu, yani her satır sonu karakterinin hemen öncesiyle eşleşir- Varsayılan durumda da
$dizgenin sonuyla eşleşir; dizgenin sonunda satır sonu karakteri varsa, o karakterin hemen öncesiyle de eşleşir
Son satır sonu karakterini hariç tutarak eşleştirmek
- Yalnızca dizgenin sonunu katı biçimde eşleştirmek için
$tek başına yetersiz kalabilir;\zve\Zson ankrajı adaylarıdır - Python düzenli ifade belgeleri ve başka bir düzenli ifade sözdizimi açıklaması temel alındığında, gerçeklemelere göre
\zve\Zdesteği ve anlamı değişir "cat\n"için farklar şöyledir- PHP:
"cat$"çok satırlı olup olmamasından bağımsız olarak eşleşir,"cat\z"eşleşmez,"cat\Z"eşleşir - ECMAScript: çok satırlı
"cat$"eşleşir, çok satırlı olmayan"cat$"eşleşmez;\zve\Zdesteklenmez - Python:
"cat$"çok satırlı olup olmamasından bağımsız olarak eşleşir;"cat\z"ve"cat\Z","cat\n"ile eşleşmez - Go ve Rust: çok satırlı
"cat$"eşleşir; çok satırlı olmayan"cat$"ve"cat\z"eşleşmez;\Zdesteklenmez - Java 8 ve .NET 7.0:
"cat$"çok satırlı olup olmamasından bağımsız olarak eşleşir,"cat\z"eşleşmez,"cat\Z"eşleşir
- PHP:
- Python’daki
\z, Python 3.14’te yeni eklendi; önceki sürümlerde desteklenmiyordu - Sondaki satır sonu karakterine izin veriliyorsa, çok satırlı moddaki
$tablodaki tüm platformlarda tutarlı biçimde"cat\n"ile eşleşir - Sondaki satır sonu karakteriyle eşleşmemek isteniyorsa çoğu platformda
\zkullanılmalı; Python 3.14 öncesinde\Z, ECMAScript’te ise çok satırlı olmayan$kullanılmalıdır - Tablodaki veriler regex101.com üzerinden toplanmıştır; gerçek çalışma zamanlarında test edilmemiştir
1 yorum
Hacker News yorumları
Eskiden beri
^işaretini “satırın başlangıcı”,$işaretini ise “satırın sonu” olarak düşünürdümDüzenli ifadelerle uğraşırken metni çoğu zaman satır satır işlediğimiz için sonuçlar sık sık aynı olur, ama o operatörü zihnimde canlandırma biçimim hâlâ “dize”den çok “satır”a yakın
Muhtemelen düzenli ifadelerle
grepüzerinden tanışmamın etkisi büyük; girdiği dize değil satır olarak görme alışkanlığı oluşmuş gibiNeredeyse 20 yıldır düzenli ifade kullanıyorum ama
$için dizenin sonu dendiğini ilk kez duyuyor gibiyim; onu hep satırın sonu olarak görmüştüm^işaretine “dizenin başlangıcı” denmesi gözüme takılıyorAslında
$nasıl “satırın sonu”ysa^de “satırın başlangıcı”; dizenin başlangıcı\A, dizenin sonu ise daha çok\Zgibi görünüyor$varsayılan olarak dizenin sonuna yönelik pozitif ileriye bakış koşulu gibi davranıyorSatır sonu karakterini eşleştirip tüketmiyor
Yalnızca çok satırlı modda satır sonu konumuyla eşleşiyor, ama o zaman da tüketmiyor gibi
Gerçekten de
$kullanarak bir satırın son karakterini yakalayıp satır sonunu tükettikten sonra sonraki satırın ilk karakterini yakalayan bir düzenli ifade oluşturamadım; yakalama grubu doğrudan$konumunda bitiyorgrepten çok Vim yerleştirdiPOSIX düzenli ifadeleri ile Python düzenli ifadeleri farklıdır
Genel olarak düzenli ifade söz dizimi evrensel değildir; bu yüzden kullandığınız gerçekleştirimin belgelerine bakmak gerekir
POSIX 9. bölüme göre düzenli ifadeler dizeler üzerinde çalışır, ancak bazı araçlar işlemeyi satır bazında sınırlar
Ayrıca
$, eşleşme hedefi dizenin sonuna sabitlenen bir çapa olarak tanımlanır; dolayısıyla$nin dize sonunu mu satır sonunu mu ifade edeceğine nihayetinde araç ya da mod karar verirgrep,sed,awk, Python gibi yaygın araçlar varsayılan olarak satır bazında çalıştığı için genellikle satır sonu olarak ele alırTek bir evrensel düzenli ifade söz dizimi yoktur
Hangi dili ve seçenekleri kullandığınızı bilmeden bir düzenli ifadeyi güvenilir biçimde okumak ya da yazmak mümkün değildir
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1...
Bu konu, Robert Elder’ı bilmeyenlere tanıtmak için tam uygun
YouTube’da ve blogunda iyi içerikler üretiyor; düzenli ifade serisinde de çeşitli araçların uyguladığı düzenli ifade davranışları arasındaki farkları epey derinlemesine inceliyor
Son videosu da iyi: https://www.youtube.com/watch?v=ys7yUyyQA-Y
HN okurlarının ilgisini çekebilecek çok içeriği var; danışmanlığın gerçekleri ve sıkıntıları gibi konulara da değiniyor
https://www.youtube.com/@RobertElderSoftware
https://blog.robertelder.org/
https://blog.robertelder.org/regular-expressions/
https://www.youtube.com/watch?v=cK87ktENPrI
Perl öğrenirken düzenli ifadeler gerçekten içselleştirdiğim ilk şeylerden biriydi; bugün bile “Camel” kitabı sayesinde Perl zihnimin bir köşesinde rahat bir yer tutuyor
Şu an en önemli bilgi gerçekleştirmeden gerçekleştirmeye değiştiği; bu yüzden bir şey üzerinde çalışırken ilgili başvuru tablosunu açıp bakma alışkanlığım oluştu
Örneğin Emacs düzenli ifadeleri
\wbiçimindeki sözcük karakterlerini desteklemiyor,\s_-benzeri karakter sınıfları kullanmak gerekiyor; bu can sıkıcı, ama Emacs’ın belgelendirme ve keşfedilebilirlik konusunda en iyisi olduğunu düşünüyorumBazı araçlarda parantezleri kaçışlamak gerekir, bazılarında gerekmez; bu davranışın yapılandırılabildiği durumlar da var, yapılandırılamadığı durumlar da
Kafa karışıklığı, sinirlenme ve inkâr aşamalarının hepsinden geçtim; artık sadece kabulleniyorum
Kavramlar her yerde aynı, ama lehçeler değişiyor
Özellikle kabukta
sed/grep/awkın GNU mu BSD mi olduğunu aklımda tutmaktansa, boru hattınaperleklemeyi çok daha sık yapıyorumPerl, klavyenin üstünde bir kedi yürümüş gibi görünüyor
Bir sürü kötü işe alım yöneticisinin “Düzenli ifadede dizenin sonunu nasıl eşleştirirsiniz?” sorusunu tuzak soru listesine eklediğini duyar gibiyim
Düzenli ifadelerle ilgili bir listeden Perl’ü çıkarmak tuhaf
perlrebelgesinde$şöyle açıklanıyor: dizenin sonuyla eşleşir; ya da dizenin sonundaki satır sonundan önceyle eşleşir;/mkullanılırsa herhangi bir satır sonundan önceyle eşleşirBu da herhalde Perl’ün bugünlerde ne kadar gündem dışına itildiğini gösteriyor
Raku, eski adıyla Perl 6,
^ve$karakterlerini dizenin başlangıcı/sonu olarak belirleyip, satır başlangıcı/sonu için^^ve$$getirdiÇok satırlı mod yok ve buna ihtiyaç da yok
\hyatay boşluk,\vise dikey boşluk anlamına da geliyorTamamen yeniden düşünülüp yeniden yazılması sayesinde, eski davranışın insanları şaşırttığı gerçeğinden ders çıkarabilmiş olmanın avantajı bu
On yıllar boyunca öğrenilmiş satır gürültüsü gibi sözdiziminin rastgele karıştırılmış hali gibi geliyor
Netlik açısından varsayılanların tam tersi olması gerekirdi
^ve$satırlar için,^^ve$$dizeler için kullanılsaydı daha doğal olurduÇünkü
^^line1$\n^line2$\n^line3$\n$gibi görünüyorÜstelik Perl 6 her yerde yok ama Perl 5 her yerde var
^^,^işaretinden daha “başlangıç gibi” görünüyorÇünkü genellikle bir satırı regex’e verip işliyorsunuz; bu yüzden tekil
^ve$işaretlerini tüm dize için kullanma tercihi, bir ölçüde geriye dönük uyumluluğu koruyorRegex’in standartlaştığını düşünen var mı, merak ediyorum
Yeni bir ortama geçtiğim her seferinde hep yeniden öğrenmem gerekti
Elbette daha fazla regex lehçesi vardır ama karşıma çıkmıyorlar; bildiklerimle çoğu işi çözebiliyorum
Kiralık araba kullanmaya benziyor
Kendi arabamdan biraz farklı hareket ediyor, eksik ve eklenmiş özellikleri var ama genel olarak çoğu oldukça benzer
Bu yüzden en azından ben regex’in yayımlanmış birden fazla resmî standart ile standartlaştırıldığını düşünüyorum
https://open-std.org/jtc1/sc22/…
https://pubs.opengroup.org/onlinepubs/9699919799/…
https://262.ecma-international.org/14.0/…
JavaScript dahil birçok sistem PCRE’yi uyguladı; çünkü Perl, POSIX sistemine çok sayıda kullanışlı genişletme ekledi
Hatırladığım kadarıyla RE2, mevcut sistemlerin performans sorunlarını ve tuhaf davranışlarını bastırmaya yönelikti; tamamının Go ile uygulandığını sanıyordum
Sonradan bakınca RE2’nin Go’dan önce çıktığını bilmiyordum
Yine de
$işaretinin anlamı ve çok satırlı moda geçme biçimi genellikle tutarlı sayılırİnsanlar dize ile satırı karıştırıyor
Dize, karakterlerden oluşan bir dizidir; satır ise iki şekilde görülebilir
Satır sonunu satır sonlandırıcısı olarak görürseniz, satır; satır sonu olmayan 0 veya daha fazla karaktere bir satır sonunun eklenmiş halidir ve sonunda satır sonu yoksa tam bir satır değildir
POSIX bu bakış açısını kullanır
Satır sonunu satır ayırıcısı olarak görürseniz, satır; satır sonu olmayan 0 veya daha fazla karakterden oluşan bir dizidir
Her iki durumda da satırın içeriği satır sonundan önce biter
^ve$işaretlerinin semantiği, tek satır modunda da çok satır modunda da satır tabanlıdırDize tabanlı semantik için, dosya işleniyorsa tüm dosya semantiği denebilecek durumlarda,
\Ave\Zya da bunların karşılığı kullanılmalıdırHer iki yorumun da avantajları var
Metin seri bağlantı üzerinden iletilirken satır sonunu satır sonlandırıcısı yapmak, tam bir satır alıp almadığınızı anlamayı kolaylaştırır
Metin dosyalarında satır sonunu satır ayırıcısı olarak görmek, son satırın hatalı durumda olmamasını sağladığı için kullanışlı olabilir; ancak satır sonlandırıcısı kullanmak, eksik yazılmış bir satırı tespit etmeyi sağlar
Bu yüzden Ruby tabanlı uygulamalarda birkaç kez ciddi bug çıktı
Her zaman
\A\zkullanılmalıhttps://homakov.blogspot.com/2012/05/saferweb-injects-in-var...
https://sakurity.com/blog/2015/02/28/openuri.html
https://sakurity.com/blog/2015/06/04/mongo_ruby_regexp.html