3 điểm bởi GN⁺ 14 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Biểu thức chính quy có tính năng và cú pháp được hỗ trợ khác nhau tùy từng triển khai, nên một mẫu dùng được trong một công cụ có thể thất bại hoặc cần chỉnh sửa trong môi trường khác
  • Càng quen với những môi trường nhiều tính năng như Perl, bạn càng thường gặp vấn đề tương thích; nếu tính cả các máy tính không có quyền cài đặt, dùng tập con chung sẽ an toàn hơn
  • Nếu định nghĩa “ở mọi nơi” theo cách nghiêm ngặt nhất, phạm vi sẽ hẹp đến mức chỉ còn literal, lớp ký tự […] và các ký tự đặc biệt cơ bản như . * ^ $
  • Nếu dùng GNU sed, awk, grep cùng với tùy chọn -E của sedgrep, tập tính năng chung có thể dùng được sẽ rộng hơn, nhưng trong tổ hợp này awk nhìn chung trở thành mẫu số chung nhỏ nhất
  • Emacs cần dấu gạch chéo ngược cho +? ( ) { } |, và ý nghĩa của \s, \S cũng khác, nên nếu muốn dùng cùng một biểu thức chính quy trên nhiều công cụ thì phải kiểm tra cả cú pháp ngoại lệ

Vì sao tính tương thích của biểu thức chính quy lại khó

  • Bất tiện lớn nhất của biểu thức chính quy đến từ khác biệt giữa các triển khai
    • Một tính năng được hỗ trợ trong công cụ này có thể hoàn toàn không có trong công cụ khác
    • Ngay cả cùng một tính năng, cú pháp cũng có thể khác đôi chút
  • Perl là một môi trường biểu thức chính quy có nhiều tính năng, nên những tính năng tưởng như hiển nhiên theo chuẩn Perl đôi khi lại thiếu trong các môi trường khác
  • Cũng có thể dùng các lựa chọn thay thế giống Perl trong những công cụ khác, nhưng chúng không mang tính chuẩn, khiến bạn khó gửi mã có thể chạy ngay cho đồng nghiệp hoặc khách hàng
  • Nếu tính cả tình huống phải làm việc trên máy tính không thể cài đặt phần mềm, cần một cách tiếp cận là tìm tập con các tính năng biểu thức chính quy hoạt động trên nhiều môi trường
  • Càng định nghĩa “ở mọi nơi” nghiêm ngặt, số tính năng có thể dùng càng giảm
    • Literal
    • Lớp ký tự […]
    • Các ký tự đặc biệt . * ^ $

Phạm vi chung trong sed, awk, grep và Emacs

  • Nếu thu hẹp các công cụ mục tiêu còn sed, awk, grep và Emacs, có thể nới lỏng tiêu chí “ở mọi nơi” một chút
  • Khi dùng các phiên bản GNU của sed, awk, grep và áp dụng tùy chọn -E cho sedgrep, danh sách tính năng chung sẽ rộng hơn
    • Tính năng biểu thức chính quy của ba công cụ này khá giống nhau
    • Các tính năng của awk nhìn chung cũng được các công cụ khác hỗ trợ
    • Ngoại lệ là ranh giới từ: trong awk dùng \<, \>, khác với \b, \B
  • Emacs tương ứng với hầu hết tính năng của awk, nhưng có khác biệt về cú pháp
    • Để + ? ( ) { } | có vai trò giống trong awk, cần đặt dấu gạch chéo ngược ở phía trước
    • Biểu thức tương ứng với \s, \S của awk trong Emacs là \s-, \S-
  • Trong Emacs, \s, \S không phải là khoảng trắng/không phải khoảng trắng mà bắt đầu một lớp ký tự
    • Lớp - nghĩa là khoảng trắng
    • \s. là ký tự dấu câu
    • \S. là ký tự không phải dấu câu
  • Theo tiêu chí này, các tính năng có thể dùng gồm
    • .
    • ^, $
    • […], [^…]
    • *
    • \w, \W, \s, \S
    • Tham chiếu ngược từ \1 đến \9
    • \b, \B
    • ?, +
    • Lựa chọn thay thế |
    • Số lần lặp {n,m}
    • Nhóm bắt (...)
  • Tuy nhiên, gawk hỗ trợ tham chiếu ngược trong chuỗi thay thế, nhưng không hỗ trợ tham chiếu ngược trong chính biểu thức chính quy
  • look-around có thể được xem là tính năng nâng cao, còn \d có thể trông như tính năng cơ bản dành cho chữ số, nhưng không được hỗ trợ trong nhiều biến thể biểu thức chính quy

1 bình luận

 
Ý kiến trên Hacker News
  • Với Emacs thì đặc biệt vất vả, vì gần như phải đoán xem cần escape cái gì
    Cũng có một lựa chọn thay thế tên là rx[0], nhưng dùng thực tế thì không vui vẻ gì
    Không chỉ cú pháp regex, mà cả ở bước sử dụng thực tế cũng thường phát sinh vấn đề về encoding và escape
    Nhập regex trong shell thì phải escape cho đúng, còn trong Python thì phải kiểm tra xem có phải raw string hay không
    Dù vậy, việc cách dùng regex trong phần lớn công cụ đã hội tụ trong một phạm vi tương đối giống nhau gần như là một phép màu thời hiện đại
    [0]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx...

    • Mọi thứ còn thú vị hơn khi viết Python sinh ra shell script có chứa regex
      Các tình huống lồng nhiều quy tắc escape khác nhau cứ liên tục xảy ra
    • Nếu cố tìm điểm tích cực, thì khi đối tượng tìm kiếm là mã Elisp, việc () được match theo nghĩa ký tự nguyên văn cũng hơi tiện
    • Regex lẽ ra nên là một ngôn ngữ có cấu trúc, chứ không phải một mớ hỗn tạp của nhiều DSL
  • Có vẻ tác giả gần như chạm tới kết luận nhưng chưa nói hẳn ra: rốt cuộc POSIX basic regular expressions hoạt động ở mọi nơi
    Tuy nhiên có kèm lưu ý rằng không phải ai cũng đã bắt kịp Single Unix Specification ấn bản 8, và trong ấn bản đó BRE đã thay đổi đôi chút

    • Đánh giá đó có vẻ không công bằng với tác giả
      Nếu không có những lưu ý như vậy thì ngay từ đầu đã chẳng cần viết bài đó
  • Trước đây tôi từng viết một bài báo về việc tìm các regex match theo cùng một cách dưới cả hai kiểu ngữ nghĩa tham lamngữ nghĩa leftmost maximal
    https://par.nsf.gov/servlets/purl/10534654

  • Tôi luôn khá khó tính trong việc phải làm rõ một công cụ chấp nhận ngôn ngữ regex nào, và nó match cái gì trong số chuỗi con bất kỳ, tiền tố, hậu tố, toàn bộ chuỗi, một dòng, hay chuỗi con trong một dòng
    Có [những loại phổ biến hơn][1] ở đây, ngoài ra còn có PCRE và Python
    Tôi đã mất một thời gian mới biết rằng một số dạng cũ thấy trong những nơi như grep [được đặc tả trong POSIX][2]
    [1]: https://cppreference.com/cpp/regex#Regular_expression_gramma...
    [2]: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd...

  • Muốn chia sẻ trang về regex của Russ Cox
    Tôi thấy đây là tài liệu hay, đáng đọc
    https://swtch.com/~rsc/regexp/

  • Vì những lý do như vậy, RFC 9485, I-Regexp: An Interoperable Regular Expression Format, rất quan trọng
    https://datatracker.ietf.org/doc/html/rfc9485

  • Gói regexp trong thư viện chuẩn của Go không hỗ trợ backreference vì dùng engine RE2
    Có thể dùng trong thay thế, nhưng không dùng được khi match

    • regexp không dùng re2, mà là một bản triển khai riêng của cùng ý tưởng
  • Sau khi gặp những bực bội tương tự với rule engine, template engine và các engine kiểu IFTTT, tôi đã tạo một thư viện Rust cho JSONLogic và cũng dùng các binding cho ngôn ngữ khác
    https://github.com/GoPlasmatic/datalogic-rs

  • Trong tài liệu JSON Schema cũng có một tập con regex được khuyến nghị
    https://json-schema.org/understanding-json-schema/reference/...