Extraire une sous-chaîne d'une chaîne dans Ruby à l'aide d'une expression régulière

130

Comment puis-je extraire une sous-chaîne d'une chaîne dans Ruby?

Exemple:

String1 = "<name> <substring>"

Je veux extraire substringde String1(c'est-à-dire tout ce qui se trouve dans la dernière occurrence de <et >).

Madhusudhan
la source

Réponses:

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

scancrée un tableau qui, pour chaque <item>in String1contient le texte entre le <et le >dans un tableau à un élément (car lorsqu'il est utilisé avec une expression régulière contenant des groupes de capture, scan crée un tableau contenant les captures pour chaque correspondance). lastvous donne le dernier de ces tableaux et firstvous donne ensuite la chaîne qu'il contient.

sepp2k
la source
320
"<name> <substring>"[/.*<([^>]*)/,1]
=> "substring"

Pas besoin d'utiliser scan, si nous n'avons besoin que d'un seul résultat.
Pas besoin d'utiliser Python match, quand on a Ruby String[regexp,#].

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

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

Nakilon
la source
37
Inutile de discréditer d'autres solutions parfaitement valables (et pourrais-je dire, plus lisibles).
coreyward
41
@coreyward, s'ils sont meilleurs, veuillez argumenter. Par exemple, la solution de sepp2k est plus flexible, et c'est pourquoi j'ai pointé if we need only one resultma solution. Et match()[]c'est plus lent, car il s'agit de deux méthodes au lieu d'une.
Nakilon
4
C'est la plus rapide de toutes les méthodes présentées, mais même la méthode la plus lente ne prend que 4,5 microsecondes sur ma machine. Je me fiche de spéculer sur les raisons pour lesquelles cette méthode est plus rapide. En performance, la spéculation est inutile . Seule la mesure compte.
Wayne Conrad
8
Je trouve cette solution plus simple et pertinente (puisque je suis nouveau sur Ruby). Merci.
Ryan H.
La lisibilité @Nakilon peut l'emporter sur de minuscules différences de performances lorsque l'on considère le succès global d'un produit et d'une équipe, donc coreyward a fait un commentaire valable. Cela dit, je pense que cela string[regex]peut être tout aussi lisible dans ce scénario, c'est donc ce que j'ai utilisé personnellement.
Nick
24

Vous pouvez utiliser une expression régulière pour cela assez facilement…

Permettre des espaces autour du mot (mais ne pas les garder):

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

Ou sans les espaces autorisés:

str.match(/<([^>]+)>\Z/)[1]
coreyward
la source
1
Je ne suis pas sûr que le dernier <>doive être le dernier de la chaîne. Si par exemple la chaîne foo <bar> bazest autorisée (et supposée donner le résultat bar), cela ne fonctionnera pas.
sepp2k
Je suis juste allé basé sur l'exemple de chaîne qu'il a fourni.
coreyward
10

Voici une approche légèrement plus flexible utilisant la matchméthode. Avec cela, vous pouvez extraire plus d'une chaîne:

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
la source
3

Une analyse plus simple serait:

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