2011-11-28 17 views
28

Corrispondenza abbastanza frequente con le espressioni regolari. In Java:..Corrispondenza con un'espressione regolare in Scala

java.util.regex.Pattern.compile ("\ w +") matcher ("this_is") partite

Ouch. Scala ha molte alternative.

  1. "\\w+".r.pattern.matcher("this_is").matches
  2. "this_is".matches("\\w+")
  3. "\\w+".r unapplySeq "this_is" isDefined
  4. val R = "\\w+".r; "this_is" match { case R() => true; case _ => false}

Il primo è altrettanto pesante come il codice Java.

Il problema con il secondo è che non è possibile fornire un modello compilato ("this_is".matches("\\w+".r")). (Questo sembra essere un anti-pattern poiché quasi ogni volta che c'è un metodo che prende una regex per compilare c'è un sovraccarico che prende una regex).

Il problema con il terzo è che abusa di unapplySeq e quindi è criptico.

Il quarto è grande quando si decompongono parti di un'espressione regolare, ma è troppo pesante quando si desidera solo un risultato booleano.

Mi manca un modo semplice per verificare le corrispondenze con un'espressione regolare? C'è un motivo per cui String#matches(regex: Regex): Boolean non è definito? In effetti, dove è definito String#matches(uncompiled: String): Boolean?

+3

Vale la pena notare che 'String # matches (string: String)' non è definito né dalla specifica 2.9 né da [StringLike] (http://www.scala-lang.org/api/current/index.html # scala.collection.immutable.StringLike) digita dalla libreria standard. È, infatti, un artefatto della definizione di [Strings in Java] (http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#matches (java.lang. Stringa)). – ig0774

+0

Non capisco cosa intendi per troppo pesante nel primo esempio? Vuoi dire che il codice è troppo lungo, o vuoi dire che sta facendo troppo lavoro? –

+1

troppo codice, il lavoro è esattamente quello che voglio – schmmd

risposta

31

è possibile definire un modello come questo:

scala> val Email = """(\w+)@([\w\.]+)""".r 

findFirstIn tornerà Some[String] se corrisponde o altrimenti None.

scala> Email.findFirstIn("[email protected]") 
res1: Option[String] = Some([email protected]) 

scala> Email.findFirstIn("test") 
rest2: Option[String] = None 

Si potrebbe anche estrarre:

scala> val Email(name, domain) = "[email protected]" 
name: String = test 
domain: String = example.com 

Infine, è anche possibile utilizzare convenzionale metodo String.matches (e anche riciclare la precedenza definito Email Regexp:.

scala> "[email protected]".matches(Email.toString) 
res6: Boolean = true 

Spero che questo vi aiuterà

+0

Sì, suppongo di poter fare "" ""^(\ w +) $ "" ". FindFirstIn (" test_string ")' ... – schmmd

+1

@schmmd non dimenticare '.r' per costruire un' Regex'. – David

+0

Oops! non sarebbe bello avere "partite" definite in "Regex"? – schmmd

12

Ho creato un piccolo pattern "Pimp my Library" per quel problema Forse ti aiuterà.

import util.matching.Regex 

object RegexUtils { 
    class RichRegex(self: Regex) { 
    def =~(s: String) = self.pattern.matcher(s).matches 
    } 
    implicit def regexToRichRegex(r: Regex) = new RichRegex(r) 
} 

Esempio di utilizzo

scala> import RegexUtils._ 
scala> """\w+""".r =~ "foo" 
res12: Boolean = true 
+1

Fantastico! Anche se chiamerei l'operatore '~' piuttosto che '~ =' perché gli operatori che finiscono in '=' mi sembrano come mutazioni sul posto (da convenzioni C++ e Python ...). –

+0

Sì, stavo mirando a perl's = ~ ma ho ottenuto il nome all'indietro, apparentemente. –

+0

Ho solo pensato di menzionare che Haskell ha anche l'operatore = ~ per la corrispondenza alle regex. Ho visto '~ =' usato per dire non-uguali, come '! ='. – eriksensei

3

Io di solito uso

val regex = "...".r 
if (regex.findFirstIn(text).isDefined) ... 

ma credo che sia abbastanza imbarazzante.

Problemi correlati