Regex là gì? Hướng dẫn biểu thức chính quy cho lập trình viên

Regex là gì?

Regex (regular expression, hay biểu thức chính quy) là một chuỗi ký tự đặc biệt dùng để định nghĩa một mẫu (pattern) tìm kiếm, xác thực và xử lý văn bản trong chương trình. Thay vì viết từng bước kiểm tra chuỗi, lập trình viên viết một pattern và để engine regex giải quyết, giúp xử lý văn bản nhanh và chính xác hơn hẳn.

Khái niệm này bắt nguồn từ toán học gia Stephen Cole Kleene vào năm 1951 với lý thuyết ngôn ngữ chính quy (regular language), sau đó được phổ biến qua các công cụ Unix như sed, awk, grep và giờ có mặt trong mọi ngôn ngữ lập trình hiện đại. Đây là kỹ năng gần như bắt buộc với bất kỳ lập trình viên nào.

Cú pháp cơ bản

Ký tự đặc biệt

  • . – khớp bất kỳ ký tự nào (trừ xuống dòng)
  • ^ – bắt đầu chuỗi, $ – kết thúc chuỗi
  • – escape ký tự đặc biệt (. khớp dấu chấm thật)
  • | – toán tử “hoặc” (a|b khớp a hoặc b)

Lớp ký tự (character classes)

  • [abc] – một trong các ký tự a, b, c; [^abc] – ngược lại
  • [a-z] – khoảng ký tự từ a đến z
  • d – chữ số [0-9], w – ký tự word [a-zA-Z0-9_], s – khoảng trắng
  • b – ranh giới từ: bcatb khớp “cat” nhưng không khớp “catalog”

Bộ định lượng (quantifiers)

  • * – 0 hoặc nhiều lần; + – 1 hoặc nhiều lần; ? – 0 hoặc 1 lần
  • {n} – chính xác n lần; {n,} – ít nhất n lần; {n,m} – từ n đến m lần
  • *?, +? – phiên bản lazy (khớp ít nhất có thể)

Nhóm và lookaround

  • (...) – capturing group, lưu kết quả vào bộ nhớ
  • (?:...) – non-capturing group, chỉ nhóm không lưu
  • (?=...) – lookahead dương, (?!...) – lookahead âm
  • (?<=...) – lookbehind dương, (?<!...) – lookbehind âm

Ví dụ: (?<=d)[a-z]+(?=d) lấy chuỗi chữ cái nằm giữa hai chữ số trong “123abc123” → kết quả “abc”.

Mẫu regex thường dùng

Email

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$

Số điện thoại Việt Nam

^(+84|84|0)[3-9]d{8}$

URL

^https?://[w.-]+(?:.[w.-]+)+(?:/[w._~:/?#[]@!$&'()*+,;=-]*)?$

Mật khẩu mạnh

^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])[A-Za-zd@$!%*?&]{8,}$

Mẫu trên yêu cầu ít nhất 8 ký tự gồm chữ thường, chữ hoa, số và ký tự đặc biệt. Lưu ý regex không thể kiểm tra email 100% theo chuẩn RFC 5322, nên chỉ dùng cho validation cơ bản và luôn xác minh thêm qua link xác nhận.

Các phiên bản regex phổ biến

Flavor Đặc điểm
PCRE/PCRE2 Phổ biến nhất, đầy đủ tính năng; dùng trong PHP, Nginx, Rust; regex101 mặc định PCRE2
JavaScript Tích hợp sẵn, cú pháp /pattern/flags; có test(), match(), replace()
Python re Standard library; dùng raw string r"...", hàm re.match(), re.findall(), re.sub()
POSIX ERE/BRE Chuẩn UNIX, dùng trong grep, sed, awk; ít tính năng hơn PCRE
Go/Rust regexp Đảm bảo thời gian chạy tuyến tính O(n), không backtracking

Mẹo tối ưu và tránh ReDoS

Regex có thể gây lỗ hổng ReDoS (Regular Expression Denial of Service) khi pattern backtracking quá nhiều trên input không khớp, ví dụ ^(a+)+$ chạy trên chuỗi “aaaaaaaaaaaaaaaaab”. Cách xử lý: dùng atomic group (?>...) hoặc possessive quantifier a++ (PCRE2), hoặc viết lại pattern đơn giản hơn.

  • Dùng re.compile() trong Python khi tái sử dụng pattern nhiều lần
  • Ưu tiên non-capturing group (?:...) khi không cần lưu kết quả
  • Tránh greedy quantifier không cần thiết, dùng *? thay *
  • Luôn test pattern trên nhiều loại input trước khi đưa vào production

Các trường hợp sử dụng chính

Xác thực đầu vào

Regex là công cụ số một để kiểm tra định dạng dữ liệu nhập từ người dùng: email, số điện thoại, mật khẩu độ mạnh, ngày tháng, mã bưu điện hay số căn cước. Thay vì viết hàng chục dòng điều kiện phức tạp, một pattern ngắn gọn thay thế toàn bộ.

Tìm kiếm và thay thế

Tìm ký tự đặc biệt trong văn bản lớn, đổi định dạng ngày từ DD/MM/YYYY sang YYYY-MM-DD, làm sạch dữ liệu bằng cách loại bỏ ký tự không mong muốn. Đây là thao tác phổ biến trong các IDE và công cụ xử lý log.

Phân tách và trích xuất dữ liệu

Trích xuất thông tin từ log file, parse CSV/XML/JSON đơn giản, lọc ra URL, email, số điện thoại từ văn bản thuần. Regex cho phép tokenizer cho ngôn ngữ dịch và lọc dữ liệu đầu vào API nhanh chóng.

Cách dùng trong Python và JavaScript

Trong Python, module re nằm trong standard library với các hàm chính re.match(), re.search(), re.findall(), re.sub(), re.split(). Quy tắc quan trọng là luôn dùng raw string r"pattern" để tránh xung đột với backslash, và dùng re.compile() khi tái sử dụng pattern nhiều lần để tối ưu hiệu suất.

Trong JavaScript, regex được viết với cú pháp /pattern/flags (ví dụ /hello/i – không phân biệt hoa thường) và có các method test(), match(), replace(), split(). Từ ES2018 trở đi, JavaScript hỗ trợ thêm named groups (?<name>...), lookbehind và unicode property p{...}.

Các flag (cờ hiệu) thường dùng: i – không phân biệt hoa thường, g – match toàn bộ trong JavaScript, m – multi-line để ^$ khớp mỗi dòng, s – dotall cho phép . khớp cả xuống dòng, x – verbose mode cho phép viết comment trong pattern (Python).

Bộ định lượng và nhóm nâng cao

Ngoài nhóm thông thường, regexp hỗ trợ named capturing group (?<name>...) giúp đọc kết quả rõ ràng hơn khi có nhiều nhóm, và backreference 1 để tham chiếu lại nhóm đã bắt – hữu ích khi cần tìm cặp ký tự lặp lại như tag HTML mở/đóng. Alternation | cho phép khớp nhiều lựa chọn trong một pattern, ví dụ (cat|dog) khớp “cat” hoặc “dog”.

Ví dụ tìm email xuất hiện trong đoạn văn bản dài, regexp [w.+-]+@[w-]+.[w.]+ sẽ quét và trích xuất toàn bộ địa chỉ email. Ví dụ tìm số điện thoại Việt Nam linh hoạt: (+84|84|0)[3-9]d{8} – xử lý cả mã quốc gia +84 lẫn số bắt đầu bằng 0 thường gặp.

Công cụ hỗ trợ luyện tập

Công cụ tốt nhất hiện nay là regex101.com – hỗ trợ PCRE2, JavaScript, Python, Go, Java, .NET, Rust, POSIX với debug realtime, giải thích pattern tự động và thư viện mẫu cộng đồng. Ngoài ra có regexper.com vẽ sơ đồ đường ray (railroad diagram) trực quan, và debuggex.com cho JavaScript, Python, PCRE. Trong IDE, VS Code hỗ trợ regex ở tìm/thay thế (Ctrl+F), JetBrains có regex tester tích hợp.

Tổng kết: hãy bắt đầu từ cú pháp cơ bản (., *, +, [], d, w), thực hành trên regex101 và luôn nhớ kiểm tra hiệu suất để tránh ReDoS. Tham khảo thêm tài liệu chính thức của Python re module, hướng dẫn regex JavaScript của MDN và bài tổng quan trên Wikipedia.

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Zig là gì? Ngôn ngữ lập trình hệ thống thay thế C

Zig là gì? Zig là ngôn ngữ lập trình hệ thống được Andrew Kelley phát triển từ năm 2015, ra mắt phiên bản ổn định 1.0 vào tháng 3 năm…

Xem thêm

Vue.js là gì? Framework JavaScript dễ học cho người mới

Vue.js (thường gọi là Vue, phát âm /vjuː/) là một khung làm việc (framework) JavaScript mã nguồn mở dùng để xây dựng giao diện người dùng (UI) và ứng dụng…

Xem thêm

SQLite là gì? Hướng dẫn cơ sở dữ liệu nhúng cho người mới

SQLite là gì? Đây là cơ sở dữ liệu SQL nhẹ nhàng nhất thế giới, được sử dụng trong mọi smartphone, trình duyệt web và hàng tỷ ứng dụng trên…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất