Làm thế nào để phù hợp với tất cả các lần xuất hiện của một regex


586

Có cách nào nhanh chóng để tìm mọi kết quả của biểu thức chính quy trong Ruby không? Tôi đã xem qua đối tượng Regex trong Ruby STL và tìm kiếm trên Google nhưng không có kết quả.


3
Tôi đọc được đây là cách tôi có thể tìm kiếm một chuỗi cho tất cả các mẫu regex và bị nhầm lẫn khủng khiếp ...
Hugoagogo

Câu trả lời:


821

Sử dụng scannên thực hiện các mẹo:

string.scan(/regex/)

9
Nhưng những gì abut trường hợp này? "khớp với tôi!". quét (/.../) = ["mat", "ch" "tôi!" ], nhưng tất cả các lần xuất hiện của /.../ sẽ là ["mat", "atc", "tch", "ch", ...]
Michael Dickens

13
Không phải vậy đâu. /.../ là một regrec tham lam bình thường. Nó sẽ không quay lại nội dung phù hợp. bạn có thể thử sử dụng regrec lười biếng nhưng thậm chí điều đó có lẽ sẽ không đủ. hãy xem tài liệu regrec ruby-doc.org/core-1.9.3/Regapi.html để thể hiện chính xác biểu thức chính quy của bạn :)
Jean

49
nó có vẻ giống như Ruby WTF ... tại sao lại có trên String thay vì Regapi với các công cụ regrec khác? Nó thậm chí không được đề cập ở bất cứ đâu trên các tài liệu cho
Regapi

9
Tôi đoán đó là vì nó được định nghĩa và được gọi trên String chứ không phải trên Regex ... Nhưng nó thực sự có ý nghĩa. Bạn có thể viết biểu thức chính quy để ghi lại tất cả các kết quả bằng cách sử dụng đối sánh Regex # và lặp lại trên các nhóm đã bắt. Ở đây bạn viết một hàm so khớp một phần và muốn nó được áp dụng lần thứ hai trên một chuỗi đã cho, đây không phải là trách nhiệm của Regapi. Tôi khuyên bạn nên kiểm tra việc triển khai quét để hiểu rõ hơn: ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean

9
@MichaelDickens: Trong trường hợp này, bạn có thể sử dụng /(?=(...))/.
Konrad Borowski

67

Để tìm tất cả các chuỗi phù hợp, sử dụng scanphương thức của String .

str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]

Nếu bạn muốn, MatchDatađó là loại đối tượng được trả về bởi matchphương thức Regapi , hãy sử dụng:

str.to_enum(:scan, /\d+/).map { Regexp.last_match }
#=> [#<MatchData "54">, #<MatchData "3">, #<MatchData "1">, #<MatchData "7">, #<MatchData "3">, #<MatchData "36">, #<MatchData "0">]

Lợi ích của việc sử dụng MatchDatalà bạn có thể sử dụng các phương pháp như offset:

match_datas = str.to_enum(:scan, /\d+/).map { Regexp.last_match }
match_datas[0].offset(0)
#=> [2, 4]
match_datas[1].offset(0)
#=> [7, 8]

Xem những câu hỏi này nếu bạn muốn biết thêm:

Đọc sách về biến đặc biệt $&, $', $1, $2trong Ruby sẽ rất hữu ích quá.


12

nếu bạn có một biểu thức chính quy với các nhóm:

str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/

bạn có thể sử dụng scanphương thức của String để tìm các nhóm khớp:

str.scan re
#> [["54"], ["1"], ["3"]]

Để tìm mẫu phù hợp:

str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]

str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]là thành ngữ hơnstr.to_enum(:scan,re).map {$&}
Tin Man

Có thể bạn hiểu lầm. Biểu thức chính quy của ví dụ về người dùng tôi đã trả lời là: /(\d+)[m-t]/không /\d+[m-t]/viết: re = /(\d+)[m-t]/; str.scan(re)giống nhau str.scan(/(\d+)[mt]/)nhưng tôi nhận được #> [["" 54 "], [" 1 "], [" 3 "]]và không "54m", "1t", "3r"]Câu hỏi là: nếu tôi có biểu thức chính quy với một nhóm và muốn chụp tất cả các mẫu mà không thay đổi thông thường biểu hiện (rời nhóm), làm thế nào tôi có thể làm điều đó? Theo nghĩa này, một giải pháp khả thi, mặc dù hơi khó hiểu và khó đọc, là:str.to_enum(:scan,re).map {$&}
MVP

-1

Bạn có thể sử dụng string.scan(your_regex).flatten. Nếu regex của bạn chứa các nhóm, nó sẽ trả về trong một mảng đơn giản.

string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]

Regex có thể là một nhóm được đặt tên là tốt.

string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten

Bạn cũng có thể sử dụng gsub, đó chỉ là một cách nữa nếu bạn muốn MatchData.

str.gsub(/\d/).map{ Regexp.last_match }

Xóa nhóm từ your_regex = /(\d+)[m-t]/và bạn sẽ không cần sử dụng flatten. Ví dụ cuối cùng của bạn sử dụng last_matchtrong trường hợp này có thể là an toàn, nhưng là toàn cầu và có thể được ghi đè nếu có bất kỳ biểu thức chính nào được khớp trước khi gọi last_match. Thay vào đó, nó có thể an toàn hơn để sử dụng string.match(regex).captures # => ["group_photo", "jpg"]hoặc string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]như thể hiện trong các câu trả lời khác, tùy thuộc vào mẫu và nhu cầu.
Tin Man
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.