Làm cách nào để viết một câu lệnh Ruby switch (trường hợp… khi nào) với regex và backreferences?


86

Tôi biết rằng tôi có thể viết một câu lệnh trường hợp Ruby để kiểm tra sự khớp với một biểu thức chính quy. Tuy nhiên, tôi muốn sử dụng dữ liệu đối sánh trong câu lệnh trả về của mình. Một cái gì đó giống như mã bán giả này:

foo = "10/10/2011"

case foo
    when /^([0-9][0-9])/
        print "the month is #{match[1]}"
    else
        print "something else"
end

Làm thế nào tôi có thể đạt được điều đó?

Cảm ơn!


Chỉ cần lưu ý: Tôi hiểu rằng tôi sẽ không bao giờ sử dụng câu lệnh switch cho một trường hợp đơn giản như trên, nhưng đó chỉ là một ví dụ. Trên thực tế, những gì tôi đang cố gắng đạt được là sự kết hợp của nhiều cụm từ thông dụng tiềm năng cho một ngày có thể được viết theo nhiều cách khác nhau, sau đó phân tích cú pháp nó với lớp Ngày của Ruby cho phù hợp.


1
Ruby's Date.parse hiểu nhiều định dạng ngày tháng. Bạn đã thử chưa?
raine

Mặc dù nó không trả lời câu hỏi này, nhưng bạn có thể muốn xem viên đá quý Chronic ...
DGM

Câu trả lời:


153

Các tham chiếu đến các nhóm đối sánh regex mới nhất luôn được lưu trữ trong các biến giả $1 để $9:

case foo
when /^([0-9][0-9])/
    print "the month is #{$1}"
else
    print "something else"
end

Bạn cũng có thể sử dụng $LAST_MATCH_INFObiến giả để lấy toàn bộ MatchDatađối tượng. Điều này có thể hữu ích khi sử dụng các ảnh chụp có tên:

case foo
when /^(?<number>[0-9][0-9])/
    print "the month is #{$LAST_MATCH_INFO['number']}"
else
    print "something else"
end

1
@Yossi Bạn có nguồn cho nhận xét của mình về vấn đề an toàn luồng không? Tôi vừa thực hiện một thử nghiệm trong ruby ​​1.8.7 có vẻ như chỉ ra rằng nó an toàn theo luồng! (Chủ đề phù hợp với một regex mỗi một giây - kiểm tra trong IRB nếu trận đấu địa phương được nhận clobbered)
Joel

5
-1 $ biến để thực hiện với biểu thức chính quy không phải là toàn cục mặc dù nó có ký hiệu đô la phía trước.
Andrew Grimm

@AndrewGrimm Cảm ơn bạn đã chỉ ra điều này. Tôi không biết về nó. Tôi sẽ phải thay đổi rất nhiều mã cũ: - /
Yossi

Bạn cũng có thể làm $1, $2... $9hoặc Regexp.last_match(1)theo khuyến cáo của rubocop
Edgar Ortega

6

Đây là một cách tiếp cận thay thế giúp bạn có được kết quả tương tự nhưng không sử dụng công tắc. Nếu bạn đặt các biểu thức chính quy của mình trong một mảng, bạn có thể làm như sau:

res = [ /pat1/, /pat2/, ... ]
m   = nil
res.find { |re| m = foo.match(re) }
# Do what you will with `m` now.

Khai báo mbên ngoài khối cho phép nó vẫn có sẵn sau khi findhoàn thành với khối và findsẽ dừng ngay sau khi khối trả về giá trị thực để bạn có được hành vi tắt giống như một công tắc cung cấp cho bạn. Điều này cung cấp cho bạn đầy đủ MatchDatanếu bạn cần (có lẽ bạn muốn sử dụng các nhóm nắm bắt được đặt tên trong các regex của mình) và tách các regex của bạn khỏi logic tìm kiếm của bạn một cách độc đáo (có thể hoặc không mang lại mã rõ ràng hơn), bạn thậm chí có thể tải các regex của mình từ một tệp cấu hình hoặc chọn tập hợp chúng bạn muốn tại thời điểm chạy.


Tôi cũng đã suy nghĩ về an toàn luồng bằng cách sử dụng casephương pháp này. Có lẽ bạn muốn sử dụng cách tiếp cận mu trong một kịch bản ren, chứ không phải là một biến toàn cầu với phương pháp trường hợp (?)
Casper
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.