Wyodrębnij podciąg z łańcucha w Rubim, używając wyrażenia regularnego

133

Jak mogę wyodrębnić podciąg z ciągu w Rubim?

Przykład:

String1 = "<name> <substring>"

Chcę wyodrębnić substringz String1(tj. Wszystko w ostatnim wystąpieniu <i >).

Madhusudhan
źródło

Odpowiedzi:

136
String1.scan(/<([^>]*)>/).last.first

scantworzy tablicę, która dla każdego <item>in String1zawiera tekst między znakami <a >w tablicy jednoelementowej (ponieważ w przypadku użycia z wyrażeniem regularnym zawierającym grupy przechwytywania, scan tworzy tablicę zawierającą przechwycenia dla każdego dopasowania). lastdaje ci ostatnią z tych tablic, a firstnastępnie daje ci ciąg w niej.

sepp2k
źródło
325
"<name> <substring>"[/.*<([^>]*)/,1]
=> "substring"

Nie ma potrzeby używania scan, jeśli potrzebujemy tylko jednego wyniku.
Nie ma potrzeby używania Pythona match, skoro mamy Rubiego String[regexp,#].

Zobacz: http://ruby-doc.org/core/String.html#method-i-5B-5D

Uwaga: str[regexp, capture] → new_str or nil

Nakilon
źródło
37
Nie ma potrzeby dyskredytowania innych, doskonale słusznych (i mogę sądzić, bardziej czytelnych) rozwiązań.
coreyward
41
@coreyward, jeśli są lepsi, proszę, argumentujcie. Na przykład rozwiązanie sepp2k jest bardziej elastyczne i dlatego wskazałem if we need only one resultw moim rozwiązaniu. I match()[]jest wolniejszy, ponieważ to dwie metody zamiast jednej.
Nakilon
4
Jest to najszybsza ze wszystkich przedstawionych metod, ale nawet najwolniejsza metoda zajmuje na moim komputerze tylko 4,5 mikrosekundy. Nie chcę spekulować, dlaczego ta metoda jest szybsza. Pod względem wydajności spekulacje są bezużyteczne . Liczy się tylko pomiar.
Wayne Conrad,
8
Uważam, że to rozwiązanie jest prostsze i na temat (ponieważ jestem nowy w Rubim). Dzięki.
Ryan H.
@Nakilon Czytelność może przeważyć drobne różnice w wydajności, biorąc pod uwagę ogólny sukces produktu i zespołu, więc coreyward przedstawił ważny komentarz. To powiedziawszy, myślę, że string[regex]w tym scenariuszu może być równie czytelny, więc tego właśnie użyłem osobiście.
Nick
25

Możesz łatwo użyć wyrażenia regularnego…

Zezwalanie na spacje wokół słowa (ale ich nie zachowywanie):

str.match(/< ?([^>]+) ?>\Z/)[1]

Lub bez dozwolonych spacji:

str.match(/<([^>]+)>\Z/)[1]
coreyward
źródło
1
Nie jestem pewien, czy ta ostatnia <>faktycznie musi być ostatnią rzeczą w ciągu. Jeśli np. String foo <bar> bazjest dozwolony (i ma dać wynik bar), to nie zadziała.
wrzesień
Po prostu poszedłem na podstawie podanego przez niego przykładowego ciągu.
coreyward
10

Oto nieco bardziej elastyczne podejście przy użyciu tej matchmetody. Dzięki temu możesz wyodrębnić więcej niż jeden ciąg:

s = "<ants> <pants>"
matchdata = s.match(/<([^>]*)> <([^>]*)>/)

# Use 'captures' to get an array of the captures
matchdata.captures   # ["ants","pants"]

# Or use raw indices
matchdata[0]   # whole regex match: "<ants> <pants>"
matchdata[1]   # first capture: "ants"
matchdata[2]   # second capture: "pants"
Grant Birchmeier
źródło
3

Prostszy skan to:

String1.scan(/<(\S+)>/).last
Navid
źródło