$pada Pythonredapat cocok tidak hanya dengan akhir string, tetapi juga dengan posisi tepat sebelum newline terakhir di akhir string, meskipun mode multiline dimatikan- Jangan berasumsi bahwa karena
^tampak berarti “awal string”, maka$juga bekerja sepenuhnya simetris; makna sebenarnya berbeda-beda bergantung pada implementasi ekspresi reguler - Hasil
$,\z, dan\Zterhadap"cat\n"berbeda antara PHP, ECMAScript, Python, Go, Java 8, .NET 7.0, dan Rust;\zdi Python baru ditambahkan pada Python 3.14 - Jika newline di akhir diperbolehkan,
$dalam mode multiline cocok dengan"cat\n"di semua platform dalam tabel, tetapi jika ingin mencocokkan hanya akhir tanpa newline, pilihan sintaksnya berbeda - Jika tidak boleh mencocokkan newline terakhir, pada sebagian besar platform gunakan
\z, sedangkan sebelum Python 3.14 dan di ECMAScript perlu mempertimbangkan alternatif masing-masing
Posisi yang dicocokkan $ di Python re
- Dalam modul ekspresi reguler Python
re,$dapat cocok dengan akhir string atau tepat sebelum newline terakhir di akhir string, meskipun mode multiline dimatikan cat$tampak sederhana karena cocok dengan"lolcat"dan tidak cocok dengan"internet cat video", tetapi hasilnya bisa berbeda dari dugaan jika ada newline di akhir seperti"cat\n"- Jika
re.MULTILINEditentukan,$cocok dengan akhir string dan akhir setiap baris, yaitu tepat sebelum setiap newline - Pada nilai default pun,
$cocok dengan akhir string, dan jika ada newline di akhir string, juga cocok tepat sebelum newline tersebut
Mencocokkan dengan mengecualikan newline terakhir
- Untuk mencocokkan akhir string secara ketat,
$saja bisa tidak cukup, dan\zserta\Zmenjadi kandidat anchor akhir - Berdasarkan dokumentasi ekspresi reguler Python dan penjelasan sintaks ekspresi reguler lainnya, dukungan dan makna
\zserta\Zberbeda-beda menurut implementasi - Perbedaannya untuk
"cat\n"adalah sebagai berikut- PHP:
"cat$"cocok terlepas dari apakah multiline aktif atau tidak,"cat\z"tidak cocok, dan"cat\Z"cocok - ECMAScript:
"cat$"dalam mode multiline cocok,"cat$"tanpa multiline tidak cocok, dan\zserta\Ztidak didukung - Python:
"cat$"cocok terlepas dari apakah multiline aktif atau tidak, sedangkan"cat\z"dan"cat\Z"tidak cocok dengan"cat\n" - Go dan Rust:
"cat$"dalam mode multiline cocok,"cat$"tanpa multiline dan"cat\z"tidak cocok, sedangkan\Ztidak didukung - Java 8 dan .NET 7.0:
"cat$"cocok terlepas dari apakah multiline aktif atau tidak,"cat\z"tidak cocok, dan"cat\Z"cocok
- PHP:
\zdi Python baru ditambahkan pada Python 3.14, dan tidak didukung pada versi sebelumnya- Jika newline di akhir diperbolehkan,
$dalam mode multiline secara konsisten cocok dengan"cat\n"di semua platform dalam tabel - Jika tidak ingin mencocokkan newline di akhir, pada sebagian besar platform gunakan
\z; sebelum Python 3.14 gunakan\Z, sedangkan di ECMAScript gunakan$tanpa multiline - Data dalam tabel dikumpulkan dari regex101.com, bukan diuji dengan runtime sebenarnya
1 komentar
Komentar Hacker News
Sejak dulu saya menganggap
^sebagai “awal baris” dan$sebagai “akhir baris”Saat menangani regex, teks sering diproses per baris sehingga hasilnya sering sama, tetapi cara saya membayangkan operator itu tetap lebih dekat ke “baris” daripada “string”
Mungkin karena saya pertama mengenal regex lewat
grep, jadi terbiasa melihat input sebagai baris, bukan stringSaya sudah memakai regex hampir 20 tahun, tapi rasanya baru kali ini mendengar bahwa
$adalah akhir string; saya selalu menganggapnya akhir baris^sebagai “awal string”Sebenarnya, seperti
$adalah “akhir baris”,^juga “awal baris”, dan awal string tampaknya lebih dekat ke\A, sedangkan akhir string ke\Z$secara default berperilaku seperti positive lookahead assertion untuk akhir stringIa tidak mencocokkan dan mengonsumsi karakter newline
Hanya dalam mode multi-baris ia cocok dengan posisi newline, tetapi bahkan saat itu tampaknya tetap tidak mengonsumsinya
Nyatanya, dengan memakai
$, saya tidak bisa membuat regex yang menangkap karakter terakhir sebuah baris, mengonsumsi newline, lalu menangkap karakter pertama baris berikutnya; grup tangkapnya hanya berakhir di$grep, melainkan Vim yang menanamkan persepsi ituRegex POSIX dan regex Python berbeda
Secara umum, sintaks regex tidak universal, jadi kita harus melihat dokumentasi implementasi yang dipakai
Menurut POSIX Bab 9, regex bekerja di atas string, tetapi sebagian utilitas membatasi pemrosesan per baris
Selain itu,
$disebut sebagai anchor yang dipatok ke akhir string target pencocokan, jadi pada akhirnya apakah$berarti akhir string atau akhir baris ditentukan oleh utilitas atau modeAlat umum seperti
grep,sed,awk, dan Python pada dasarnya bekerja per baris, sehingga biasanya memperlakukannya sebagai akhir barisTidak ada satu sintaks regex universal
Tanpa mengetahui bahasa dan opsi yang digunakan, kita tidak bisa membaca atau menulis regex dengan andal
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1...
Topik ini pas sekali untuk memperkenalkan Robert Elder kepada yang belum mengenalnya
Ia membuat konten bagus di YouTube dan blog, dan dalam seri regex-nya ia menggali cukup dalam perbedaan perilaku regex yang diimplementasikan berbagai alat
Video terbarunya juga bagus: https://www.youtube.com/watch?v=ys7yUyyQA-Y
Ada banyak konten yang mungkin menarik bagi pembaca HN, termasuk topik seperti realitas dan kesulitan dunia konsultasi
https://www.youtube.com/@RobertElderSoftware
https://blog.robertelder.org/
https://blog.robertelder.org/regular-expressions/
https://www.youtube.com/watch?v=cK87ktENPrI
Saat belajar Perl, regex adalah salah satu hal pertama yang benar-benar meresap ke tubuh saya, dan sampai sekarang Perl masih terasa nyaman di sudut hati saya berkat buku “Camel”
Pengetahuan terpenting sekarang adalah bahwa setiap implementasi berbeda, jadi saya jadi terbiasa membuka tabel referensi terkait setiap kali mengerjakan sesuatu
Misalnya, regex Emacs tidak mendukung karakter kata berbentuk
\wdan harus memakai kelas karakter mirip\s_-, yang menyebalkan, tetapi menurut saya Emacs unggul dalam dokumentasi dan kemudahan ditemukanAda utilitas yang mengharuskan escape tanda kurung dan ada yang tidak, dan perilaku ini kadang bisa dikonfigurasi, kadang tidak
Setelah melewati semua tahap bingung, kesal, dan penyangkalan, sekarang saya menerimanya saja
Konsepnya sama di mana-mana, tetapi dialeknya berbeda
Khususnya di shell, daripada memikirkan apakah
sed/grep/awkitu GNU atau BSD, jauh lebih sering saya menyelipkanperlke dalam pipelinePerl terlihat seperti kucing menginjak keyboard
Rasanya terdengar suara banyak manajer perekrutan yang buruk menambahkan “bagaimana mencocokkan akhir string dalam regex?” ke daftar pertanyaan jebakan mereka
Aneh rasanya mengeluarkan Perl dari daftar terkait regex
Dalam dokumentasi
perlre,$dijelaskan begini: cocok dengan akhir string, atau cocok sebelum newline di akhir string, atau jika memakai/m, cocok sebelum newline mana punMungkin itu juga menunjukkan betapa Perl belakangan ini sudah terdorong keluar dari perhatian
Raku, yang dulu dikenal sebagai Perl 6, menetapkan
^dan$sebagai awal/akhir string, lalu memperkenalkan^^dan$$sebagai awal/akhir barisTidak ada mode multibaris, dan memang tidak diperlukan
\hjuga berarti spasi horizontal, sedangkan\vberarti spasi vertikalKarena semuanya dipikirkan ulang dan ditulis ulang sepenuhnya, ada keuntungan bisa belajar dari fakta bahwa perilaku lama mengejutkan banyak orang
Rasanya seperti sintaks line noise yang sudah dipelajari selama puluhan tahun dicampur secara acak
Akan lebih jelas kalau default-nya justru kebalikan
Rasanya lebih alami jika
^dan$dipakai untuk baris, sedangkan^^dan$$untuk stringKarena tampilannya seperti
^^line1$\n^line2$\n^line3$\n$Selain itu, Perl 6 tidak ada di mana-mana, tetapi Perl 5 ada di mana-mana
^^terlihat lebih “seperti awal” daripada^Karena biasanya baris dimasukkan ke regex untuk diproses, pilihan memakai
^dan$tunggal untuk seluruh string mempertahankan kompatibilitas mundur sampai batas tertentuSaya bertanya-tanya apakah ada orang yang menganggap regex sudah distandarkan
Setiap kali pindah ke lingkungan baru, saya selalu harus mempelajarinya lagi
Mungkin ada lebih banyak dialek regex, tetapi saya tidak menemuinya, dan dengan yang saya tahu sebagian besar masalah bisa diselesaikan
Mirip seperti mengemudikan mobil sewaan
Gerakannya sedikit berbeda dari mobil sendiri, ada fitur yang hilang dan ada fitur tambahan, tetapi secara keseluruhan kebanyakan cukup mirip
Jadi setidaknya menurut saya regex telah distandarkan dalam beberapa standar resmi yang dipublikasikan
https://open-std.org/jtc1/sc22/…
https://pubs.opengroup.org/onlinepubs/9699919799/…
https://262.ecma-international.org/14.0/…
Banyak sistem, termasuk JavaScript, mengimplementasikan PCRE, karena Perl menambahkan banyak ekstensi berguna ke skema POSIX
Seingat saya, RE2 lebih berusaha menekan masalah performa dan perilaku khas dari skema yang ada, dan saya kira semuanya diimplementasikan dengan Go
Belakangan saya baru tahu bahwa RE2 muncul lebih dulu daripada Go
Meski begitu, makna
$dan cara mengubahnya dengan mode multibaris biasanya cukup konsistenOrang-orang mencampuradukkan string dan baris
String adalah sekuens karakter, sedangkan baris bisa dilihat dengan dua cara
Jika newline dianggap sebagai terminator baris, maka baris adalah nol atau lebih karakter non-newline yang diikuti newline, dan jika tidak ada newline di akhir, itu bukan baris yang lengkap
POSIX memakai sudut pandang ini
Jika newline dianggap sebagai pemisah baris, maka baris adalah sekuens nol atau lebih karakter non-newline
Dalam kedua penafsiran, isi baris berakhir sebelum newline
Semantik
^dan$, baik dalam mode satu baris maupun mode multibaris, bersifat berbasis barisUntuk semantik berbasis string—atau jika menangani berkas, bisa juga dianggap sebagai semantik seluruh berkas—harus memakai
\Adan\Zatau padanannyaKedua interpretasi punya kelebihan
Saat mengirim teks melalui koneksi serial, menjadikan newline sebagai terminator baris memudahkan mengetahui apakah baris lengkap sudah diterima
Pada berkas teks, melihat newline sebagai pemisah baris bisa lebih nyaman karena baris terakhir tidak menjadi dalam keadaan salah, tetapi dengan terminator baris kita bisa mendeteksi baris yang ditulis tidak lengkap
Karena hal ini, beberapa bug serius pernah terjadi di aplikasi berbasis Ruby
Harus selalu memakai
\A\zhttps://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