Czy istnieje szybki sposób na znalezienie każdego dopasowania wyrażenia regularnego w Ruby? Przejrzałem obiekt Regex w Ruby STL i szukałem w Google bezskutecznie.
Czy istnieje szybki sposób na znalezienie każdego dopasowania wyrażenia regularnego w Ruby? Przejrzałem obiekt Regex w Ruby STL i szukałem w Google bezskutecznie.
Odpowiedzi:
Korzystanie scan
powinno załatwić sprawę:
string.scan(/regex/)
/(?=(...))/
.
Aby znaleźć wszystkie pasujące ciągi, użyj scan
metody Ciąg .
str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]
Jeśli chcesz, MatchData
czyli typu obiektu zwracanego przez match
metodę Regexp , użyj:
str.to_enum(:scan, /\d+/).map { Regexp.last_match }
#=> [#<MatchData "54">, #<MatchData "3">, #<MatchData "1">, #<MatchData "7">, #<MatchData "3">, #<MatchData "36">, #<MatchData "0">]
Zaletą korzystania MatchData
jest to, że możesz używać metod takich jak 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]
Zobacz te pytania, jeśli chcesz dowiedzieć się więcej:
Czytając o zmiennych specjalnych $&
, $'
, $1
, $2
Ruby będzie też pomocny.
jeśli masz wyrażenie regularne z grupami:
str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/
możesz użyć scan
metody String, aby znaleźć pasujące grupy:
str.scan re
#> [["54"], ["1"], ["3"]]
Aby znaleźć pasujący wzór:
str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]
jest bardziej idiomatyczny niżstr.to_enum(:scan,re).map {$&}
/(\d+)[m-t]/
nie /\d+[m-t]/
pisać: re = /(\d+)[m-t]/; str.scan(re)
jest to samo, str.scan(/(\d+)[mt]/)
ale dostaję #> [["" 54 "], [" 1 "], [" 3 "]]
i nie "54m", "1t", "3r"]
Pytanie brzmiało: czy mam wyrażenie regularne z grupą i chcę uchwycić wszystkie wzorce bez zmiany regularnego wyrażenie (opuszczenie grupy), jak mogę to zrobić? W tym sensie możliwym rozwiązaniem, choć nieco tajemniczym i trudnym do odczytania, było:str.to_enum(:scan,re).map {$&}
Możesz użyć string.scan(your_regex).flatten
. Jeśli wyrażenie regularne zawiera grupy, zwróci się w jednej prostej tablicy.
string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]
Regex może być również nazwaną grupą.
string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten
Możesz także użyć gsub
, to tylko jeden sposób, jeśli chcesz MatchData.
str.gsub(/\d/).map{ Regexp.last_match }
your_regex = /(\d+)[m-t]/
i nie będziesz musiał używać flatten
. Ostatni przykład użycia, last_match
który w tym przypadku jest prawdopodobnie bezpieczny, ale jest globalny i może zostać zastąpiony, jeśli jakieś wyrażenie regularne zostanie dopasowane przed wywołaniem last_match
. Zamiast tego jest to prawdopodobnie bezpieczniejsze w użyciu string.match(regex).captures # => ["group_photo", "jpg"]
lub string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
jak pokazano w innych odpowiedziach, w zależności od wzorca i potrzeb.