2011-10-03 12 views
6

Immagino che questo sarà uno stupido errore ma per me, il seguente ritorna un array contenente solo "M". Vedi questo:Ruby Regex, solo una cattura (molto semplice!)

/(.)+?/.match("Many many characters!").captures 
=> ["M"] 

Perché non restituisce un array di ogni carattere? Devo aver perso qualcosa di evidentemente evidente perché non riesco a vedere che cosa c'è di sbagliato in questo?

Modifica: ho appena realizzato, non ho bisogno del +? ma ancora non funziona senza di esso.

Modifica: Scuse! Chiarirò: il mio obiettivo è consentire agli utenti di inserire un'espressione regolare e uno stile e un file di testo di input, ovunque ci sia una corrispondenza, il testo sarà circondato da un elemento html e lo stile verrà applicato, non sto solo dividendo il testo stringa in caratteri, ho usato solo la regex dato perché era il più semplice anche se era stupido da parte mia. Come ottengo i gruppi di cattura da scan() o non è possibile? Vedo che $ 1 contiene "!" (ultima partita?) e non altri.

Modifica: Accidenti, non è davvero il mio giorno. Come mi ha informato injekt, le acquisizioni sono archiviate in array separati. Come ottengo l'offset di queste acquisizioni dalla stringa originale? Mi piacerebbe essere in grado di ottenere l'offset di una cattura quindi circondarlo con un'altra stringa. O è quello che sta per gsub? (Ho pensato che solo sostituito il match, non un gruppo di cattura)

Speriamo montaggio finale: destro, vorrei solo iniziare di nuovo: P

così, ho una stringa. L'utente utilizzerà un file di configurazione per inserire un'espressione regolare, quindi uno stile associato a ciascun gruppo di acquisizione. Devo essere in grado di scansionare l'intera stringa e ottenere l'inizio e la fine o l'offset e la dimensione di ogni corrispondenza di gruppo.

Quindi, se un utente ha configurato ([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4}) (indirizzo e-mail), allora dovrei essere in grado di ottenere:

[ ["elliotpotts", 0, 11], 
    ["sample.",  12, 7], 
    ["com",   19, 3] ] 

dalla stringa: "[email protected]"

Se questo non è chiaro, c'è semplicemente qualcosa di sbagliato in me: P. Grazie mille finora ragazzi, e grazie per essere così paziente!

+0

Ho appena visto la modifica, i gruppi di acquisizione dalla scansione sono memorizzati in array separati, basta provare l'espressione regolare e una stringa di prova in irb vedrai. Le risposte rimangono le stesse con la modifica inclusa –

+0

Hai appena visto la tua prossima modifica, dovrai aggiornarla con ulteriori informazioni. Sono un po 'confuso ora: P Sentiti libero di lanciare un esempio più completo, non importa quanto sia inventato, quindi sappiamo esattamente cosa devi estrarre –

+0

Ok, ho aggiornato la mia risposta con la tua ultima modifica. Sono un po 'legato per il momento in questo momento quindi è solo la soluzione completa senza spiegazione, fammi sapere se non ha senso e lo aggiornerò –

risposta

9

Perché la cattura è solo la corrispondenza una singolo carattere.(.)+ non è lo stesso di (.+)

>> /(.)+?/.match("Many many characters!").captures 
=> ["M"] 
>> /(.+)?/.match("Many many characters!").captures 
=> ["Many many characters!"] 
>> /(.+?)/.match("Many many characters!").captures 
=> ["M"] 

Se si desidera far corrispondere ogni personaggio in modo ricorsivo utilizzare String#scan o String#split se non si cura di gruppi di acquisizione

Utilizzando scansione:

"Many many characters!".scan(/./) 
#=> ["M", "a", "n", "y", " ", "m", "a", "n", "y", " ", "c", "h", "a", "r", "a", "c", "t", "e", "r", "s", "!"] 

Nota quell'altra risposta sta usando (.) mentre va bene se ti interessa il gruppo di cattura, è un po 'inutile se non lo fai, altrimenti restituirà OGNI CARATTERE in esso è ow n Array separata, in questo modo:

[["M"], ["a"], ["n"], ["y"], [" "], ["m"], ["a"], ["n"], ["y"], [" "], ["c"], ["h"], ["a"], ["r"], ["a"], ["c"], ["t"], ["e"], ["r"], ["s"], ["!"]] 

In caso contrario, basta usare split: "Many many characters!".split(' ')"

EDIT In risposta alla tua modifica:

reg = /([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/ 
str = "[email protected]" 
str.scan(reg).flatten.map { |capture| [capture, str.index(capture), capture.size] } 
#=> [["elliotpotts", 0, 11], ["sample.", 12, 7], ["com", 19, 3]]` 

Oh, e non hai bisogno di scansione , non stai davvero scannerizzando così non hai bisogno di attraversare, almeno non con l'esempio che hai fornito:

lavorerà anche

+0

Grazie! Ho anche trovato una risposta alternativa e la pubblicherò ora. Grazie! – Ell

+0

I due frammenti di codice indicati non funzionano correttamente per gli offset nel caso generale, funzionano solo se le sottostringhe corrispondenti sono tutte diverse. Se, ad esempio, ci sono 3 corrispondenze per "h", allora lo stesso indice (la prima istanza di "h") viene restituito tutte e 3 volte. lo str.index (capture) restituisce l'indice dell'istanza FIRST della sottostringa acquisita. – jpwynn

0

Restituisce un solo carattere perché è tutto ciò che gli hai chiesto di abbinare. Probabilmente si desidera utilizzare scan invece:

str = "Many many characters!" 
matches = str.scan(/(.)/) 
1

Sì, qualcosa di importante è stato mancato ;-)

(...) introduce solo un gruppo di cattura: il numero di volte che il gruppo di partite è irrilevante come l'indice è determinato solo dal regolare espressione stessa e non l'input.

La chiave è una "espressione regolare globale", che applicherà l'espressione regolare più volte nell'ordine. In Ruby questo è fatto con l'inversione Regex#match-String#scan (molte altre lingue hanno una "/ g" modificatore di espressione regolare):

"Many many chara­cters!".sc­an(/(.)+?/­) 
# but more simply (or see answers using String#split) 
"Many many chara­cters!".sc­an(/(.)/­) 

Felice di codifica

0

Il seguente codice è da Get index of string scan results in ruby e modificato per i miei gusti .

[].tap {|results| 
    "abab".scan(/a/) {|capture| 
     results.push(([capture, Regexp::last_match.offset(0)]).flatten) 
    } 
} 

=> [["a", 0], ["a", 2]]