2011-11-17 19 views
11

Attualmente sto cercando di trovare una regex che possa suddividere una stringa in parole in cui le parole sono definite come una sequenza di caratteri circondata da spazi bianchi o racchiusa tra virgolette. Sto usando String#scanRuby regex che estrae le parole

Per esempio, la stringa:

' hello "my name" is "Tom"' 

dovrebbe abbinare le parole:

hello 
my name 
is 
Tom 

sono riuscito a corrispondere le parole racchiuse tra virgolette utilizzando:

/"([^\"]*)"/ 

ma non riesco a capire come incorporare i caratteri circondati da spazi bianchi prendi 'hello', 'is' e 'Tom' mentre allo stesso tempo non sbagliare 'il mio nome'.

Qualsiasi aiuto con questo sarebbe apprezzato!

risposta

23
result = ' hello "my name" is "Tom"'.split(/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/) 

funzionerà per voi. Stamperà

=> ["", "hello", "\"my name\"", "is", "\"Tom\""] 

Basta ignorare le corde vuote.

Spiegazione

" 
\\s   # Match a single character that is a “whitespace character” (spaces, tabs, and line breaks) 
    +    # Between one and unlimited times, as many times as possible, giving back as needed (greedy) 
(?=   # Assert that the regex below can be matched, starting at this position (positive lookahead) 
    (?:   # Match the regular expression below 
     [^\"]   # Match any character that is NOT a “\"” 
     *    # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
     \"    # Match the character “\"” literally 
     [^\"]   # Match any character that is NOT a “\"” 
     *    # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
     \"    # Match the character “\"” literally 
    )*   # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
    [^\"]   # Match any character that is NOT a “\"” 
     *    # Between zero and unlimited times, as many times as possible, giving back as needed (greedy) 
    \$    # Assert position at the end of a line (at the end of the string or before a line break character) 
) 
" 

È possibile utilizzare reject come questo per evitare di stringhe vuote

result = ' hello "my name" is "Tom"' 
      .split(/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/).reject {|s| s.empty?} 

stampe

=> ["hello", "\"my name\"", "is", "\"Tom\""] 
+0

+1. Buona risposta! – Swanand

+0

Grande dissezione della regex. Molto utile. –

+0

questo non rimuove i caratteri speciali .. –

4
text = ' hello "my name" is "Tom"' 

text.scan(/\s*("([^"]+)"|\w+)\s*/).each {|match| puts match[1] || match[0]} 

produce:

hello 
my name 
is 
Tom 

Spiegazione:

0 o più spazi seguiti da

sia

alcune parole all'interno di doppi apici O

una sola parola

seguito da 0 o più spazi

+0

Ciò che l'OP sta chiedendo, non è possibile senza guardare avanti. – Swanand

+1

Non sono sicuro del motivo per cui penseresti che ... –

+0

Lo intendevo per la soluzione originale, in cui solo una regex viene utilizzata per la divisione. Qualsiasi elaborazione successiva non era ciò che avevo in mente. – Swanand

1

Si può provare questo regex:

/\b(\w+)\b/ 

che utilizza \b per trovare il limite di parola. E questo sito web http://rubular.com/ è utile.

+3

Questo non funziona, non fa alcun tentativo di catturare tra le virgolette come una singola corrispondenza –