2013-02-27 21 views
7

Sono nuovo di scala. Sto cercando di abbinare una stringa delimitata da virgolette doppie, e io sono un po 'perplesso per il seguente comportamento:Scala Espressioni regolari (stringa delimitata da virgolette)

se faccio la seguente:

val stringRegex = """"([^"]*)"(.*$)""" 
val regex = stringRegex.r 
val tidyTokens = Array[String]("1", "\"test\"", "'c'", "-23.3") 
tidyTokens.foreach { 
    token => if (token.matches (stringRegex)) println (token + " matches!") 
} 

ottengo

"test" matches! 

altrimenti , se faccio la seguente:

tidyTokens.foreach { 
    token => token match { 
     case regex(token) => println (token + " matches!") 
     case _ => println ("No match for token " + token) 
    } 
} 

ottengo

No match for token 1 
No match for token "test" 
No match for token 'c' 
No match for token -23.3 

Perché il "test" non corrisponde nel secondo caso?

risposta

9

Prendete la vostra espressione regolare:

"([^"]*)"(.*$) 

quando si compila con .r, questa stringa produce un oggetto regex - che, se corrisponde è stringa di input, deve cedere stringhe catturate - uno per il ([^"]*) e l'altro per lo (.*$). Il tuo codice

case regex(token) => ... 

dovrebbe riflettere questo, in modo forse si vuole

case regex(token, otherStuff) => ... 

O semplicemente

case regex(token, _) => ... 

Perché? Perché la sintassi case regex(matchedCaputures...) funziona perché regex è un oggetto con un metodo unapplySeq. case regex(token) => ... traduce (approssimativamente) a:

case List(token) => ... 

Dove List(token) è ciò regex.unapplySeq(inputString) rendimenti:

regex.unapplySeq("\"test\"") // Returns Some(List("test", "")) 

tuo regex fa corrispondere alla stringa "test" ma nella dichiarazione case il metodo del estrattore regex unapplySeq restituisce un elenco di 2 stringhe perché è quello che dice la regex che cattura. Questo è sfortunato, ma il compilatore non può aiutarti qui perché le espressioni regolari sono compilate da stringhe in fase di runtime.

Un'alternativa sarebbe quella di utilizzare un gruppo di non cattura:

val stringRegex = """"([^"]*)"(?:.*$)""" 
//        ^^ 

Poi il codice avrebbe funzionato, perché regex sarà ora un oggetto estrattore cui unapplySeq metodo restituisce solo un singolo gruppo catturato:

tidyTokens foreach { 
    case regex(token) => println (token + " matches!") 
    case t => println ("No match for token " + t) 
} 

Date un'occhiata al tutorial su Extractor Objects, per una migliore comprensione su come apply/unapply/012.funziona.

+0

Grazie! Anche per il riferimento agli oggetti Extractor! – gbgnv