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 >).

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.


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


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]

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"

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.