Extrahieren Sie einen Teilstring mit einem regulären Ausdruck aus einem String in Ruby

130

Wie kann ich in Ruby einen Teilstring aus einem String extrahieren?

Beispiel:

String1 = "<name> <substring>"

Ich möchte extrahieren substring aus String1(dh alles , was in den letzten Vorkommen <und >).

Madhusudhan
quelle

Antworten:

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

scanErstellt ein Array, das für jedes <item>In String1den Text zwischen dem <und dem >in einem Ein-Element-Array enthält (da bei Verwendung mit einem regulären Ausdruck, der Erfassungsgruppen enthält, der Scan ein Array erstellt, das die Erfassungen für jede Übereinstimmung enthält). lastgibt Ihnen das letzte dieser Arrays und firstgibt Ihnen dann die Zeichenfolge darin.

sepp2k
quelle
319
"<name> <substring>"[/.*<([^>]*)/,1]
=> "substring"

Keine Notwendigkeit zu verwenden scan, wenn wir nur ein Ergebnis benötigen.
Keine Notwendigkeit, Pythons zu verwenden match, wenn wir Rubys haben String[regexp,#].

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

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

Nakilon
quelle
37
Keine Notwendigkeit, andere vollkommen gültige (und vielleicht besser lesbare) Lösungen zu diskreditieren.
Coreyward
41
@coreyward, wenn sie besser sind, argumentieren Sie es bitte. Zum Beispiel ist die Lösung von sepp2k flexibler, und deshalb habe ich if we need only one resultin meiner Lösung darauf hingewiesen . Und match()[]ist langsamer, weil es zwei Methoden statt einer sind.
Nakilon
4
Dies ist die schnellste aller vorgestellten Methoden, aber selbst die langsamste Methode benötigt auf meinem Computer nur 4,5 Mikrosekunden. Ich möchte nicht spekulieren, warum diese Methode schneller ist. In der Leistung ist Spekulation nutzlos . Nur die Messung zählt.
Wayne Conrad
8
Ich finde diese Lösung einfacher und auf den Punkt (da ich neu bei Ruby bin). Vielen Dank.
Ryan H.
@Nakilon Die Lesbarkeit kann winzige Leistungsunterschiede überwiegen, wenn man den Gesamterfolg eines Produkts und eines Teams betrachtet. Daher hat coreyward einen gültigen Kommentar abgegeben. Trotzdem denke ich, dass string[regex]es in diesem Szenario genauso lesbar sein kann, also habe ich es persönlich verwendet.
Nick
24

Sie können dafür ganz einfach einen regulären Ausdruck verwenden ...

Leerzeichen um das Wort herum zulassen (aber nicht behalten):

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

Oder ohne die erlaubten Leerzeichen:

str.match(/<([^>]+)>\Z/)[1]
Coreyward
quelle
1
Ich bin mir nicht sicher, ob das Letzte <>tatsächlich das Letzte in der Zeichenfolge sein muss. Wenn zB die Zeichenfolge foo <bar> bazzulässig ist (und das Ergebnis liefern soll bar), funktioniert dies nicht.
sepp2k
Ich habe mich nur an der von ihm bereitgestellten Beispielzeichenfolge orientiert.
Coreyward
10

Hier ist ein etwas flexiblerer Ansatz mit der matchMethode. Mit dieser Option können Sie mehr als eine Zeichenfolge extrahieren:

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
quelle
3

Ein einfacherer Scan wäre:

String1.scan(/<(\S+)>/).last
Navid
quelle