Biểu thức chính quy Ruby (ruby regex cho ngắn) giúp tìm pattern cụ thể trong chuỗi, nhằm trích xuất dữ liệu xử lý tiếp.
Hai trường hợp dùng phổ biến regex: validation (xác thực) & parsing (phân tích).
Ví dụ:
Nghĩ về email, với ruby regex định nghĩa email hợp lệ trông như thế nào. Nói cách khác, chương trình phân biệt email hợp lệ & không hợp lệ.

Ruby regular expressions định nghĩa giữa hai dấu gạch chéo phân biệt với cú pháp ngôn ngữ khác. Biểu thức đơn giản khớp từ hoặc một ký tự.
Ví dụ:
# Tìm từ 'like'
"Do you like cats?" =~ /like/
Trả về chỉ số lần xuất hiện đầu nếu tìm thấy (khớp thành công) hoặc nil ngược lại. Nếu không quan tâm chỉ số dùng String#include?.
Cách khác kiểm tra chuỗi khớp regex dùng phương thức match:
if "Do you like cats?".match(/like/)
puts "Match found!"
end
Bây giờ:
Bạn học xây dựng pattern nâng cao để khớp, bắt获 (capture) & thay thế (replace) thứ như ngày, số điện thoại, email, URL, v.v.
Character Classes (Lớp Ký Tự)
Character class cho định nghĩa dải hoặc danh sách ký tự khớp. Ví dụ, [aeiou] khớp bất kỳ nguyên âm.
Ví dụ: Chuỗi chứa nguyên âm?
def contains_vowel(str)
str =~ /[aeiou]/
end
contains_vowel("test") # trả về 1
contains_vowel("sky") # trả về nil
Không tính số lượng ký tự, sẽ thấy cách làm sau.
Ranges (Dải)
Dùng ranges khớp nhiều chữ/số không gõ hết. Nói cách khác, range [2-5] giống [2345].
Một số range hữu ích:
- [0-9] khớp số 0-9
- [a-z] khớp chữ a-z (không in hoa)
- [^a-z] range phủ định
Ví dụ: Chuỗi này chứa số?
def contains_number(str)
str =~ /[0-9]/
end
contains_number("The year is 2015") # trả về 12
contains_number("The cat is black") # trả về nil
Nhớ: giá trị trả về dùng `=~` là chỉ số chuỗi hoặc `nil`
Có cú pháp viết tắt cho dải ký tự:
- \w tương đương [0-9a-zA-Z_]
- \d giống [0-9]
- \s khớp white space (tab, space, newline)
Cũng có dạng phủ định:
- \W bất kỳ không trong [0-9a-zA-Z_]
- \D không phải số
- \S không phải space
Ký tự chấm . khớp mọi thứ trừ newline. Cần dùng literal . thì escape.
Ví dụ: Escape ký tự đặc biệt
# Không escape, chữ khớp
"5a5".match(/\d.\d/)
# Chỉ literal dot khớp
"5a5".match(/\d\.\d/) # nil
"5.5".match(/\d\.\d/) # match
Modifiers (Điều Chỉnh)
Cho đến giờ chỉ khớp một ký tự. Để khớp nhiều ký tự dùng pattern modifiers.
| Modifier | Mô tả |
|---|---|
| + | 1 hoặc nhiều |
| * | 0 hoặc nhiều |
| ? | 0 hoặc 1 |
| {3,5} | giữa 3 và 5 |
Kết hợp mọi thứ học tạo regex phức tạp hơn.
Ví dụ: Có trông như địa chỉ IP?
# Lưu ý: cũng khớp IP không hợp lệ như 999.999.999.999, nhưng chỉ quan tâm format.
def ip_address?(str)
# Dùng !! chuyển giá trị trả về boolean
!!(str =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
end
ip_address?("192.168.1.1") # true
ip_address?("0000.0000") # false
Khớp Chuỗi Chính Xác
Cần khớp chính xác cần modifier khác. Xem ví dụ hiểu:
# Muốn tìm chuỗi đúng 4 ký tự, vẫn khớp vì có hơn 4, nhưng không muốn.
"Regex are cool".match /\w{4}/
# Thay vào đó dùng modifier 'đầu dòng' và 'cuối dòng'
"Regex are cool".match /^\w{4}$/
# Lần này không khớp. Ví dụ hơi gượng, có thể dùng .size độ dài, nhưng nghĩ nó truyền đạt ý tưởng.
Khớp chặt ở đầu chuỗi không phải mỗi dòng (sau \n) dùng \A và \Z thay ^ và $.
Capture Groups (Nhóm Bắt Giữ)
Với capture groups, bắt获 phần khớp và tái sử dụng sau. Để bắt获 đóng phần muốn trong ngoặc đơn.
Ví dụ: Parse file log
Line = Struct.new(:time, :type, :msg)
LOG_FORMAT = /(\d{2}:\d{2}) (\w+) (.*)/
def parse_line(line)
line.match(LOG_FORMAT) { |m| Line.new(*m.captures) }
end
parse_line("12:41 INFO User has logged in.")
# Tạo đối tượng như: #
Ví dụ này dùng .match thay =~.
Phương thức trả về MatchData nếu khớp, nil ngược lại. Lớp MatchData có nhiều phương thức hữu ích, xem tài liệu!
Muốn giá trị boolean (true/false) dùng match? từ Ruby 2.4. Cũng nhanh hơn match vì không tạo MatchData.
Truy cập dữ liệu bắt获 dùng .captures hoặc đối tượng MatchData như mảng, index 0 khớp toàn bộ, index tiếp theo chứa nhóm khớp.
Muốn capture group đầu:
m = "John 31".match /\w+ (\d+)/
m[1] # 31
Cũng có non-capturing groups. Cho nhóm biểu thức không penalty hiệu năng. Named groups hữu ích làm biểu thức phức tạp dễ đọc.
| Cú pháp | Mô tả |
|---|---|
(?:...) | Non-capturing group |
(?<foo>...) | Named group |
Ví dụ: Named Groups
m = "David 30".match /(?<name>\w+) (?<age>\d+)/
m[:age] # => "30"
m[:name] # => "David"
Named group trả về MatchData truy cập đọc kết quả.
Look Ahead & Look Behind (Nhìn Trước & Nhìn Sau)
Kỹ thuật nâng cao có thể không có mọi regex implementation. Engine regex Ruby làm được, xem cách tận dụng.
Look ahead cho phép nhìn xem có khớp cụ thể trước/sau không.
| Tên | Mô tả |
|---|---|
| (?=pat) | Positive lookahead |
| (?<=pat) | Positive lookbehind |
| (?!pat) | Negative lookahead |
| (?<!pat) | Negative lookbehind |
Ví dụ: Có số đứng sau ít nhất một chữ?
def number_after_word?(str)
!!(str =~ /(?<=\w) (\d+)/)
end
number_after_word?("Grade 99")
Lớp Regexp Ruby
Ruby regular expressions là instance lớp Regexp. Thường không dùng trực tiếp lớp này, nhưng tốt biết 🙂
puts /a/.class # Regexp
Một dùng có thể: tạo regex từ chuỗi:
regexp = Regexp.new("a")
Cách khác tạo regexp:
regexp = %r{\w+}
Regex Options (Tùy Chọn)
Set tùy chọn trên regex làm hành xử khác.
| Options | Mô tả |
|---|---|
| i | ruby regex case insensitive |
| m | dot matches newline |
| x | ignore whitespace |
Dùng tùy chọn thêm chữ cái cuối regex, sau / đóng.
Như sau:
"abc".match?(/[A-Z]/i)
Định Dạng Regex Dài
Ruby regex phức tạp khó đọc, hữu ích chia thành nhiều dòng. Làm bằng modifier 'x'. Format này cũng cho phép comment trong regex.
Ví dụ:
LOG_FORMAT = %r{
(\d{2}:\d{2}) # Time
\s(\w+) # Event type
\s(.*) # Message
}x
Ruby Regex: Gộp Tất Cả
Regular expressions dùng với nhiều phương thức Ruby.
- .split
- .scan
- .gsub
- v.v…
Ví dụ: Khớp tất cả từ từ chuỗi dùng .scan
"this is some string".scan(/\w+/) # => ["this", "is", "some", "string"]
Ví dụ: Trích xuất tất cả số từ chuỗi
"The year was 1492.".scan(/\d+/) # => ["1492"]
Ví dụ: Viết hoa tất cả từ trong chuỗi
str = "lord of the rings"
str.gsub(/\w+/) { |w| w.capitalize } # => "Lord Of The Rings"
Ví dụ: Xác thực email
email = "test@example.com"
!!email.match(/\A[\w.+-]+@\w+\.\w+\z/) # true
Ví dụ cuối dùng !! chuyển kết quả thành boolean (true/false), thay thế dùng match? Ruby 2.4+ đã làm vậy & nhanh hơn.
Kết Luận
Regular expressions tuyệt vời nhưng đôi khi hơi tricky. Công cụ như rubular.com giúp xây ruby regex tương tác hơn. Rubular cũng có cheat sheet ruby regex rất hữu ích. Bây giờ lượt bạn mở editor code!
À, đừng quên chia sẻ này với bạn bè nếu thích, để nhiều người học 🙂