Tôi nghĩ sẽ rất vui khi theo dõi bài viết ngày hôm qua về các điều kiện regex bằng cách xem một số thủ thuật đơn giản khác mà bạn có thể làm với các biểu thức chính quy trong ruby.
Tách chuỗi qua biểu thức chính quy
Có thể bạn đã khá quen thuộc với việc tách chuỗi bằng dấu phân cách văn bản:
"one,two".split(",")
# => ["one", "two"]
Nhưng bạn có biết rằng phép tách cũng sẽ chấp nhận một biểu thức chính quy không?
# use `,` and `-` as delimiters
"one,two-three".split(/,|-/)
=> ["one", "two", "three"]
# Use comma as thousands separator for US currency,
# but use a space for Euros
"1,000USD".split /(?=.*(USD))(?(1),| )/
Chụp các dấu phân cách
Đây là một mẹo nhỏ trong bữa tiệc. Thông thường, khi bạn tách một chuỗi, các dấu phân cách sẽ biến mất:
# The commas vanish!
"one,two".split(",")
# => ["one", "two"]
Nhưng nếu bạn sử dụng một biểu thức chính quy và bạn đặt dấu phân cách bên trong một nhóm, thì split
cũng sẽ chụp dấu phân cách.
"one,two-three".split(/(,|-)/)
=> ["one", ",", "two", "-", "three"]
Lý do điều này xảy ra là split
thực sự phân chia chuỗi ở ranh giới của mỗi nhóm bắt.
Lạm dụng split
Bạn có thể lạm dụng split
để làm cho nó hoạt động gần giống như match
. Trong đoạn mã bên dưới, tôi đang sử dụng bốn nhóm trong biểu thức chính quy để chia chuỗi thành 4 phần.
"1-800-555-1212".split(/(1)-(\d{3})-(\d{3})-(\d{4})/)
=> ["", "1", "800", "555", "1212"]
Mục đầu tiên trong mảng kết quả là một chuỗi trống vì biểu thức chính quy khớp với toàn bộ chuỗi nguồn.
Đối sánh toàn cầu
Theo mặc định, biểu thức chính quy sẽ chỉ khớp với một mẫu một lần. Trong đoạn mã dưới đây, chúng tôi chỉ nhận được một trận đấu mặc dù có năm trận đấu có thể xảy ra.
"12345".match /\d/
=> #<MatchData "1">
Trong các ngôn ngữ khác như Perl, giải pháp sẽ là gắn cờ biểu thức chính quy là "toàn cục". Ruby không có tùy chọn đó, nhưng nó có String#scan
phương pháp.
scan
phương thức trả về một mảng chứa tất cả các kết quả phù hợp:
"12345".scan /\d/
=> ["1", "2", "3", "4", "5"]
Nó thậm chí còn có một cú pháp khối tiện dụng:
"12345".scan /\d/ do |i|
puts i
end
Thật không may, dường như không có bất kỳ cách nào để quét một chuỗi một cách lười biếng. Vì vậy, kỹ thuật này có thể không phù hợp với - giả sử - xử lý tệp 500mb.
Quét theo nhóm
Bây giờ tại thời điểm này, tôi hy vọng bạn đang tự hỏi loại thủ thuật kỳ lạ nào chúng ta có thể thực hiện bằng cách sử dụng các nhóm trong quá trình quét của chúng tôi.
Thật không may, hành vi ở đây là hoàn toàn có thể dự đoán được và SINH RA. Các nhóm dẫn đến một mảng nhiều chiều:
"hiho hiho".scan /(hi)(ho)/
=> [["hi", "ho"], ["hi", "ho"]]
Có một trường hợp cạnh kỳ lạ. Nếu bạn sử dụng nhóm, bất kỳ thứ gì KHÔNG trong nhóm sẽ không được trả lại.
"hiho hiho".scan /(hi)ho/
=> [["hi"], ["hi"]]
Tốc ký
Tôi cá là bạn biết về =~
như một cách để kiểm tra xem một biểu thức chính quy có khớp với một chuỗi hay không. Nó trả về chỉ số của ký tự nơi trận đấu bắt đầu.
"hiho" =~ /hi/
# 0
"hiho" =~ /ho/
# 2
Tuy nhiên, có một cách nhanh chóng khác để kiểm tra một trận đấu. Tôi đang nói về ===
nhà điều hành.
/hi/ === "hiho"
# true
Khi chúng ta viết a === b
trong ruby, chúng tôi đang hỏi "b có thuộc tập hợp được xác định bởi a không". Hoặc trong trường hợp này, "'hiho' có thuộc tập hợp các chuỗi được đối sánh bởi regex /hi/
không ".
===
toán tử được sử dụng nội bộ trong các câu lệnh trường hợp của Ruby. Điều đó có nghĩa là bạn cũng có thể sử dụng biểu thức chính quy trong các câu lệnh viết hoa.
case "hiho"
when /hi/
puts "match"
end
Toán tử ba dấu bằng cũng có thể hữu ích để cho phép các phương thức của riêng bạn chấp nhận biểu thức chính quy hoặc chuỗi.
Hãy tưởng tượng rằng bạn muốn thực thi một số mã khi có lỗi xảy ra, trừ khi nó nằm trong danh sách các lớp được cấu hình sẵn để bỏ qua. Trong ví dụ dưới đây, chúng tôi sử dụng ===
toán tử để cho phép người dùng chỉ định một chuỗi hoặc một biểu thức chính quy.
def ignored?(error)
@ignored_patterns.any? { |x| x === error.class.name }
end
Vậy là xong!
Chắc chắn, có hàng tá thủ thuật nhỏ như thế này nằm rải rác khắp Ruby và Rails. Nếu có một cái bạn đặc biệt thích, hãy cho tôi biết!