2012-02-16 20 views
85

Tôi hiện đang cố gắng rexp một chuỗi thành nhiều biến. Ví dụ chuỗi:
So khớp nhóm Ruby Regexp, gán các biến trên 1 dòng

ryan_string = "RyanOnRails: This is a test" 

Tôi đã phù hợp nó với regexp này, với 3 nhóm:

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i) 

Bây giờ để truy cập mỗi nhóm tôi phải làm một cái gì đó như thế này:

ryan_group[0][0] (first group) RyanOnRails 
ryan_group[0][1] (second group) : 
ryan_group[0][2] (third group) This is a test 

Điều này có vẻ khá vô lý và cảm thấy như tôi đang làm điều gì đó sai. Tôi hy vọng sẽ có thể làm được điều gì đó như thế này:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i) 

Điều này có thể? Hoặc là có một cách tốt hơn so với cách tôi đang làm nó?

Trả lời

146

Bạn không muốn scan cho điều này, vì điều này rất có ý nghĩa. Bạn có thể sử dụng String#match sẽ trả về đối tượng MatchData, sau đó bạn có thể gọi #captures để trả về một mảng chụp. Một cái gì đó như thế này:

#!/usr/bin/env ruby 

string = "RyanOnRails: This is a test" 
one, two, three = string.match(/(^.*)(:)(.*)/i).captures 

p one #=> "RyanOnRails" 
p two #=> ":" 
p three #=> " This is a test" 

Hãy nhận biết rằng nếu không phù hợp được tìm thấy, String#match sẽ trở lại con số không, vì vậy một cái gì đó như thế này có thể làm việc tốt hơn:

if match = string.match(/(^.*)(:)(.*)/i) 
    one, two, three = match.captures 
end 

Mặc dù scan không làm cho chút ý nghĩa cho việc này. Nó vẫn thực hiện công việc, bạn chỉ cần làm phẳng mảng Array được trả về trước. one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten

+3

Hãy coi chừng rằng nếu không tìm thấy kết quả phù hợp nào, kết quả trả về không có và bạn nhận được một NilError. Nếu bạn đang ở trong Rails, tôi đề nghị bạn thay đổi: 'một, hai, ba = string.match (/(^.*)(:)(.*)/ i) .captures' vào: 'một, hai, ba = string.match (/(^.*)(:)(.*)/ i) .try (: captures)' –

+4

@AndreaSalicetti Tôi đã chỉnh sửa bài đăng của mình, tôi không thêm Rails-mã cụ thể vào nó vì vậy tôi đã thay đổi nó với một phiên bản để xử lý các đối tượng nil trả về –

+0

Sạch sẽ và gọn gàng, tất cả các quyền! –

28

Bạn có thể sử dụng Match hoặc = ~ thay vì đó sẽ cung cấp cho bạn một trận đấu duy nhất và bạn có thể truy cập dữ liệu phù hợp với cách tương tự hoặc chỉ cần sử dụng các biến trận đấu đặc biệt $ 1, $ 2, Something $ 3

như:

if ryan_string =~ /(^.*)(:)(.*)/i 
    first = $1 
    third = $3 
end 
+0

wow. ruby. Tôi không thể ngăn tôi kinh ngạc. – Gaston

+1

@Gaston thực sự là cú pháp regexp gốc có nguồn gốc từ Perl :) – ohaleck

2

scan() sẽ tìm tất cả các đối sánh không trùng lặp của regex trong chuỗi của bạn, vì vậy thay vì trả về một nhóm các nhóm như bạn mong đợi, nó sẽ trả về mảng mảng.

Bạn đang có lẽ tốt hơn bằng cách sử dụng match(), và sau đó nhận được hàng loạt các ảnh chụp bằng MatchData#captures:

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures 

Tuy nhiên bạn cũng có thể làm điều này với scan() nếu bạn muốn:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0] 
23

Bạn có thể đặt tên cho các trận đấu đã bị bắt của bạn

string = "RyanOnRails: This is a test" 
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string 
puts one, two, three 

Nó không hoạt động nếu bạn đảo ngược thứ tự chuỗi và regex.

2

Bạn phải quyết định xem đó có phải là ý tưởng tốt hay không, nhưng có thể tự động hóa regexp ruby ​​(tự động) xác định biến cục bộ cho bạn!

Tôi chưa chắc liệu tính năng này có tuyệt vời hay hoàn toàn điên rồ, nhưng regex của bạn có thể xác định các biến cục bộ.

ryan_string = "RyanOnRails: This is a test" 
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string^ 
# This defined three variables for you. Crazy, but true. 
webframework # => "RyanOnRails" 
puts "W: #{webframework} , C: #{colon}, R: #{rest}" 

(Hãy xem http://ruby-doc.org/core-2.1.1/Regexp.html, tìm kiếm "biến cục bộ").

Lưu ý: Như đã chỉ ra trong một chú thích, tôi thấy rằng có một câu trả lời tương tự và trước đó cho câu hỏi này bởi @toonsend (https://stackoverflow.com/a/21412455). Tôi không nghĩ rằng tôi đã "ăn cắp", nhưng nếu bạn muốn công bằng với lời khen ngợi và tôn vinh câu trả lời đầu tiên, cảm thấy tự do :) Tôi hy vọng không có động vật bị hại.

+0

Câu trả lời này trông khá giống với http://stackoverflow.com/a/21412455/525478, cũ hơn một năm ... –

+0

@BradWerth Tôi đoán tôi không thấy điều đó. Nhưng tôi đã cập nhật câu trả lời của tôi để bao gồm các mối quan tâm của bạn. – Felix

Các vấn đề liên quan