Jak dopasować wszystkie wystąpienia wyrażenia regularnego
586
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.
Ale co z tą sprawą? „dopasuj mnie!”. scan (/.../) = [„mat”, „ch” „me!” ], ale wszystkie wystąpienia /.../ byłyby [„mat”, „atc”, „tch”, „ch”, ...]
Michael Dickens,
13
Nie byłoby inaczej. /.../ jest normalnym, chciwym wyrażeniem regularnym. Nie cofnie się w przypadku dopasowanych treści. możesz spróbować użyć leniwego wyrażenia regularnego, ale nawet to prawdopodobnie nie wystarczy. spójrz na wyrażenie regularne doc ruby-doc.org/core-1.9.3/Regexp.html, aby poprawnie wyrazić swoje wyrażenie regularne :)
Jean
49
to wygląda jak Ruby WTF ... dlaczego to jest na String zamiast Regexp z innymi regexp? Nigdzie nie wspomniano o nim w dokumentach dotyczących
Regexp
9
Wydaje mi się, że dzieje się tak, ponieważ jest zdefiniowane i wywołane na String, a nie na Regex ... Ale to naprawdę ma sens. Możesz napisać wyrażenie regularne, aby przechwycić wszystkie dopasowania za pomocą Regex # match i iterować przechwycone grupy. Tutaj piszesz funkcję dopasowania częściowego i chcesz, aby była stosowana wiele razy na danym ciągu, nie jest to obowiązkiem Regexp. Sugeruję sprawdzenie implementacji skanu dla lepszego zrozumienia: ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean
9
@MichaelDickens: W tym przypadku możesz użyć /(?=(...))/.
Konrad Borowski
67
Aby znaleźć wszystkie pasujące ciągi, użyj scanmetody Ciąg .
str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]jest bardziej idiomatyczny niżstr.to_enum(:scan,re).map {$&}
Tin Man
Może źle zrozumiałeś. Wyrażenie regularne w przykładzie użytkownika, na który odpowiedziałem brzmiało: /(\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 {$&}
MVP
-1
Możesz użyć string.scan(your_regex).flatten. Jeśli wyrażenie regularne zawiera grupy, zwróci się w jednej prostej tablicy.
Usuń zgrupowanie your_regex = /(\d+)[m-t]/i nie będziesz musiał używać flatten. Ostatni przykład użycia, last_matchktó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.
Odpowiedzi:
Korzystanie
scan
powinno załatwić sprawę:źródło
/(?=(...))/
.Aby znaleźć wszystkie pasujące ciągi, użyj
scan
metody Ciąg .Jeśli chcesz,
MatchData
czyli typu obiektu zwracanego przezmatch
metodę Regexp , użyj:Zaletą korzystania
MatchData
jest to, że możesz używać metod takich jakoffset
:Zobacz te pytania, jeśli chcesz dowiedzieć się więcej:
Czytając o zmiennych specjalnych
$&
,$'
,$1
,$2
Ruby będzie też pomocny.źródło
jeśli masz wyrażenie regularne z grupami:
możesz użyć
scan
metody String, aby znaleźć pasujące grupy:Aby znaleźć pasujący wzór:
źródło
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.Regex może być również nazwaną grupą.
Możesz także użyć
gsub
, to tylko jeden sposób, jeśli chcesz MatchData.źródło
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łaniemlast_match
. Zamiast tego jest to prawdopodobnie bezpieczniejsze w użyciustring.match(regex).captures # => ["group_photo", "jpg"]
lubstring.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]
jak pokazano w innych odpowiedziach, w zależności od wzorca i potrzeb.