3 poin oleh GN⁺ 2024-03-21 | 1 komentar | Bagikan ke WhatsApp

Memahami perilaku karakter "$" dalam regular expression Python

  • Saat menggunakan modul re di Python, ^ dikenal berarti "awal string", dan $ dikenal berarti "akhir string".
  • Namun, $ tidak selalu hanya berarti "akhir string", dan perilakunya dapat berbeda tergantung platform.
  • Di Python, ketika mode multiline dinonaktifkan, karakter $ dapat cocok dengan akhir string atau sebelum karakter baris baru di akhir string.

Perbedaan antara akhir string dan kecocokan karakter baris baru

  • Saat mode multiline dinonaktifkan, untuk mencocokkan akhir string di Python tanpa karakter baris baru, tidak cukup hanya menggunakan $.
  • Untuk mencocokkan akhir string, \z dan \Z dapat digunakan.
  • Di Python, jika menggunakan re.MULTILINE, $ akan cocok dengan akhir string dan akhir setiap baris (tepat sebelum karakter baris baru).

Perbandingan perilaku regular expression di berbagai platform

  • Melalui tabel yang membandingkan apakah pola cocok terhadap "cat\n" di berbagai platform, terlihat bahwa jika pencocokan yang mencakup karakter baris baru diperbolehkan, maka penggunaan $ dalam mode multiline bekerja secara konsisten.
  • Jika ingin mencocokkan tanpa menyertakan karakter baris baru, maka di semua platform selain Python dan ECMAScript gunakan \z, sedangkan di Python dan ECMAScript masing-masing gunakan \Z atau $ tanpa mode multiline.

Pendapat GN⁺

  • Artikel ini dapat menjadi pengingat bagi para pengembang yang menggunakan regular expression tentang perilaku tak terduga karakter $ di Python.
  • Regular expression sangat kuat untuk pemrosesan string, tetapi perlu kehati-hatian karena perilakunya dapat berbeda antarplatform.
  • Pengembang perlu memahami perbedaan ini dan melakukan pengujian tambahan saat mengembangkan aplikasi lintas platform agar terhindar dari masalah kompatibilitas.
  • Pustaka regular expression lain yang menyediakan fungsi serupa antara lain java.util.regex di Java dan System.Text.RegularExpressions di .NET; keduanya juga perlu dipahami perbedaan perilakunya sesuai platform masing-masing.
  • Saat memperkenalkan sintaks atau perilaku regular expression yang baru, perlu mempertimbangkan kompatibilitas dengan kode yang sudah ada, dampak performa, serta kurva pembelajaran di dalam tim, lalu mengevaluasi dengan baik manfaat dan biayanya.

1 komentar

 
GN⁺ 2024-03-21
Komentar Hacker News
  • Orang yang terbiasa dengan regular expression tahu bahwa ^ berarti "awal string" dan $ berarti "akhir string". Namun secara pribadi saya memikirkan keduanya sebagai "awal baris" dan "akhir baris". Dalam kebanyakan kasus hasilnya sama karena teks diproses satu baris pada satu waktu, tetapi sudut pandang saya saat memikirkan operator ini tidak berubah. Mungkin karena saya pertama kali mengenal regular expression lewat grep dan terutama memikirkan input sebagai "baris".

    • Regular expression POSIX dan regular expression Python berbeda. Secara umum, Anda harus merujuk ke dokumentasi regular expression dari implementasi yang Anda gunakan, karena sintaksnya tidak universal.
    • Menurut POSIX Bab 9, regular expression umumnya terkait dengan pemrosesan teks dan bekerja pada string yang diakhiri NUL yang menandai akhir string. Beberapa utilitas membatasi pemrosesan pada unit baris. $ dapat berarti akhir string atau akhir baris, dan hal ini ditentukan oleh utilitas (atau mode) yang digunakan. Sebagian besar utilitas umum (grep, sed, awk, Python, dll.) secara default memperlakukannya sebagai akhir baris.
    • Tidak ada satu sintaks regular expression universal. Tanpa mengetahui bahasa dan opsi yang digunakan, Anda tidak bisa membaca atau menulis regular expression dengan andal.
  • Ini kesempatan yang sempurna untuk memperkenalkan Robert Elder. Ia membuat konten YouTube dan blog, memiliki seri tentang regular expression, dan menggali secara mendalam perbedaan perilaku berbagai alat.

  • Regular expression adalah salah satu hal pertama yang benar-benar saya internalisasi saat pertama kali belajar Perl. (Perl masih punya tempat hangat di hati saya berkat buku "Camel")

    • Informasi paling penting saat ini adalah mengetahui bahwa implementasi berbeda-beda, dan membiasakan diri membuka referensi untuk hal yang sedang dikerjakan.
    • Misalnya, regular expression Emacs menggunakan "\s_-" (atau sesuatu di layar tanpa referensi) sebagai kelas karakter alih-alih "\w", tetapi Emacs punya dokumentasi dan kemudahan penemuan fitur yang sangat baik.
    • Beberapa utilitas mengharuskan escape pada tanda kurung dan beberapa tidak. Kadang perilaku ini bisa dikonfigurasi, kadang tidak.
    • Saya telah melewati semua tahap kebingungan, kekesalan, dan penyangkalan, dan sekarang saya hanya menerimanya. Konsepnya sama di mana-mana, tetapi variasinya berubah.
  • Saya bisa membayangkan manajer perekrutan yang buruk menambahkan 'bagaimana cara mencocokkan akhir string dalam regular expression?' ke daftar pertanyaan mereka yang berisi 'ha! kamu tidak tahu trik jebakan ini ya!'.

  • Aneh jika Perl tidak dimasukkan dalam daftar saat membahas regular expression.

    • Penjelasan tentang $ dalam dokumentasi perlre: mencocokkan akhir string (atau sebelum karakter baris baru di akhir string; atau sebelum setiap baris baru jika menggunakan /m)
  • Raku (sebelumnya Perl 6) memilih ^ dan $ untuk menandai awal dan akhir string, serta memperkenalkan ^^ dan $$ untuk menandai awal dan akhir baris. Mode multi-baris tidak tersedia maupun tidak diperlukan.

    • Salah satu keuntungan dari perombakan/penulisan ulang total adalah bisa belajar dari fakta bahwa perilaku sebelumnya mengejutkan orang.
  • Adakah orang yang mengira regular expression sudah distandardisasi? Pindah ke konteks baru selalu menjadi proses belajar ulang.

  • Ada kebingungan antara string dan baris. String adalah rangkaian karakter, dan baris bisa berarti dua hal berbeda. Jika karakter baris baru dianggap sebagai terminator baris, maka baris adalah rangkaian karakter non-baris-baru termasuk karakter baris baru itu sendiri. Tanpa karakter baris baru, itu bukan baris yang lengkap. Itulah yang digunakan POSIX. Jika karakter baris baru dianggap sebagai pemisah baris, maka baris adalah rangkaian karakter non-baris-baru. Dalam kedua kasus, isi baris berakhir sebelum karakter baris baru, baik karena karakter itu mengakhiri baris maupun karena memisahkannya dari baris berikutnya.

    • Makna ^ dan $ didasarkan pada baris — terlepas dari apakah mode satu baris atau multi-baris digunakan. Untuk makna yang berbasis string — saat menangani berkas, ini juga bisa dianggap sebagai keseluruhan berkas — gunakan \A dan \Z atau padanannya.
  • Ini menyebabkan beberapa bug serius di aplikasi berbasis Ruby. Saya selalu menggunakan \A\z.