2012-02-16 12 views
85

Attualmente sto cercando di rexp una stringa in più variabili. stringa Esempio:
Ruby Regexp corrispondenza gruppo, assegnare variabili su 1 riga

ryan_string = "RyanOnRails: This is a test" 

ho abbinato con questa espressione regolare, con 3 gruppi:

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i) 

Ora per accedere ogni gruppo che devo fare qualcosa di simile:

ryan_group[0][0] (first group) RyanOnRails 
ryan_group[0][1] (second group) : 
ryan_group[0][2] (third group) This is a test 

Questo sembra abbastanza ridicolo e sembra che sto facendo qualcosa di sbagliato. Mi aspetto che sia in grado di fare qualcosa del genere:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i) 

È possibile? O c'è un modo migliore di come lo sto facendo?

risposta

146

Per questo, non ha bisogno di scan, perché ha poco senso. È possibile utilizzare String#match che restituirà un oggetto MatchData, è quindi possibile chiamare #captures per restituire una matrice di catture. Qualcosa di simile a questo:

#!/usr/bin/env ruby 

string = "RyanOnRails: This is a test" 
one, two, three = string.match(/(^.*)(:)(.*)/i).captures 

p one #=> "RyanOnRails" 
p two #=> ":" 
p three #=> " This is a test" 

essere consapevoli del fatto che se non viene trovata alcuna corrispondenza, String#match tornerà pari a zero, in modo da qualcosa di simile potrebbe funzionare meglio:

if match = string.match(/(^.*)(:)(.*)/i) 
    one, two, three = match.captures 
end 

Anche se scan non poco senso per questo. Funziona ancora, devi solo appiattire prima l'array restituito. one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten

+3

Attenzione che se non vengono trovate corrispondenze, la corrispondenza restituisce nil e ottieni un errore NilError. Se siete in Rails, suggerisco di cambiare: 'uno, due, tre = String.match (/(^.*)(:)(.*)/ i) .captures' in: 'uno, due, tre = string.match (/(^.*)(:)(.*)/ i) .try (: acquisisce)' –

+4

@AndreaSalicetti Ho modificato il mio post, non lo sono aggiungendo il codice specifico di Rails, così l'ho modificato con una versione per gestire l'oggetto nil restituito –

+0

Pulito e pulito, va bene! –

28

Si potrebbe utilizzare Match o = ~ invece che darebbe una singola partita e si potrebbe o accedere ai dati match nello stesso modo o semplicemente utilizzare le speciali variabili partita $ 1, $ 2, $ 3

Qualcosa di simile:

if ryan_string =~ /(^.*)(:)(.*)/i 
    first = $1 
    third = $3 
end 
+0

wow. rubino. Non puoi smettere di stupirmi. – Gaston

+1

@Gaston che è in realtà la sintassi regexp originale originata da Perl :) – ohaleck

2

scan() troverà tutte le partite non sovrapposti della regex nella stringa, quindi invece di restituire una serie di gruppi come ti sembra di essere in attesa, che restituisce un array di array.

si sono probabilmente meglio utilizzare match(), e quindi ottenere la matrice di cattura usando MatchData#captures:

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures 

Tuttavia si potrebbe anche fare questo con scan() se si voleva:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0] 
23

È nome delle partite catturate

string = "RyanOnRails: This is a test" 
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string 
puts one, two, three 

Non funziona se si inverte l'ordine di stringa e regex.

2

Devi decidere se è una buona idea, ma ruby ​​regexp possibile (automagicamente) definire le variabili locali per te!

Non sono ancora sicuro se questa funzione è fantastica o semplicemente totalmente folle, ma la regex può definire variabili locali.

ryan_string = "RyanOnRails: This is a test" 
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string^ 
# This defined three variables for you. Crazy, but true. 
webframework # => "RyanOnRails" 
puts "W: #{webframework} , C: #{colon}, R: #{rest}" 

(Date un'occhiata a http://ruby-doc.org/core-2.1.1/Regexp.html, della ricerca di "variabile locale").

Nota: Come sottolineato in un commento, vedo che c'è una risposta simile e precedenti a questa domanda da @toonsend (https://stackoverflow.com/a/21412455). Non penso di aver "rubato", ma se vuoi essere onesto con lodi e onorare la prima risposta, sentiti libero :) Spero che nessun animale sia stato danneggiato.

+0

Questa risposta sembra molto simile a http://stackoverflow.com/a/21412455/525478, che è più vecchia di un anno ... –

+0

@BradWerth Immagino di non averlo visto. Ma ho aggiornato la mia risposta per includere le tue preoccupazioni. – Felix

Problemi correlati