Come modellare la corrispondenza usando l’espressione regolare in Scala?

Mi piacerebbe essere in grado di trovare una corrispondenza tra la prima lettera di una parola e una delle lettere in un gruppo come “ABC”. In pseudocodice, questo potrebbe sembrare qualcosa di simile:

case Process(word) => word.firstLetter match { case([ac][AC]) => case _ => } } 

Ma come faccio ad afferrare la prima lettera in Scala invece che in Java? Come esprimo correttamente l’espressione regolare? È ansible farlo all’interno di un case class ?

È ansible farlo perché le espressioni regolari definiscono gli estrattori, ma è necessario prima definire il modello regex. Non ho accesso ad un REPL di Scala per testarlo, ma qualcosa del genere dovrebbe funzionare.

 val Pattern = "([a-cA-C])".r word.firstLetter match { case Pattern(c) => c bound to capture group here case _ => } 

Dalla versione 2.10, si può usare la funzione di interpolazione delle stringhe di Scala:

 implicit class Regex(sc: StringContext) { def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*) } scala> "123" match { case r"\d+" => true case _ => false } res34: Boolean = true 

Ancora meglio è ansible associare i gruppi di espressioni regolari:

 scala> "123" match { case r"(\d+)$d" => d.toInt case _ => 0 } res36: Int = 123 scala> "10+15" match { case r"(\d\d)${first}\+(\d\d)${second}" => first.toInt+second.toInt case _ => 0 } res38: Int = 25 

È anche ansible impostare meccanismi di associazione più dettagliati:

 scala> object Doubler { def unapply(s: String) = Some(s.toInt*2) } defined module Doubler scala> "10" match { case r"(\d\d)${Doubler(d)}" => d case _ => 0 } res40: Int = 20 scala> object isPositive { def unapply(s: String) = s.toInt >= 0 } defined module isPositive scala> "10" match { case r"(\d\d)${d @ isPositive()}" => d.toInt case _ => 0 } res56: Int = 10 

Un esempio impressionante di ciò che è ansible con Dynamic è mostrato nel post del blog Introduzione al tipo dinamico :

 object T { class RegexpExtractor(params: List[String]) { def unapplySeq(str: String) = params.headOption flatMap (_.r unapplySeq str) } class StartsWithExtractor(params: List[String]) { def unapply(str: String) = params.headOption filter (str startsWith _) map (_ => str) } class MapExtractor(keys: List[String]) { def unapplySeq[T](map: Map[String, T]) = Some(keys.map(map get _)) } import scala.language.dynamics class ExtractorParams(params: List[String]) extends Dynamic { val Map = new MapExtractor(params) val StartsWith = new StartsWithExtractor(params) val Regexp = new RegexpExtractor(params) def selectDynamic(name: String) = new ExtractorParams(params :+ name) } object p extends ExtractorParams(Nil) Map("firstName" -> "John", "lastName" -> "Doe") match { case p.firstName.lastName.Map( Some(p.Jo.StartsWith(fn)), Some(p.`.*(\\w)$`.Regexp(lastChar))) => println(s"Match! $fn ...$lastChar") case _ => println("nope") } } 

Come evidenziato da Delnan, la parola chiave match di Scala non ha nulla a che fare con le espressioni regolari. Per scoprire se una stringa corrisponde a String.matches , è ansible utilizzare il metodo String.matches . Per scoprire se una stringa inizia con a, boc in lettere minuscole o maiuscole, la regex sarà simile a questa:

 word.matches("[a-cA-C].*") 

Puoi leggere questa espressione regolare come “uno dei caratteri a, b, c, A, B o C seguito da qualsiasi cosa” ( . Significa “qualsiasi carattere” e * significa “zero o più volte”, quindi “. *” È qualsiasi stringa).

Per approfondire un po ‘ la risposta di Andrew : Il fatto che le espressioni regolari definiscano gli estrattori può essere usato per scomporre molto bene le sottostringhe adattate dalla regex usando la corrispondenza del modello di Scala, ad esempio:

 val Process = """([a-cA-C])([^\s]+)""".r // define first, rest is non-space for (p <- Process findAllIn "aha bah Cah dah") p match { case Process("b", _) => println("first: 'a', some rest") case Process(_, rest) => println("some first, rest: " + rest) // etc. } 

Si noti che l’approccio dalla risposta di @ AndrewMyers corrisponde all’intera stringa all’espressione regolare, con l’effetto di ancorare l’espressione regolare ad entrambe le estremità della stringa usando ^ e $ . Esempio:

 scala> val MY_RE = "(foo|bar).*".r MY_RE: scala.util.matching.Regex = (foo|bar).* scala> val result = "foo123" match { case MY_RE(m) => m; case _ => "No match" } result: String = foo scala> val result = "baz123" match { case MY_RE(m) => m; case _ => "No match" } result: String = No match scala> val result = "abcfoo123" match { case MY_RE(m) => m; case _ => "No match" } result: String = No match 

E con no .* Alla fine:

 scala> val MY_RE2 = "(foo|bar)".r MY_RE2: scala.util.matching.Regex = (foo|bar) scala> val result = "foo123" match { case MY_RE2(m) => m; case _ => "No match" } result: String = No match 

String.matches è il modo di fare la corrispondenza del modello nel senso regex.

Ma a parte il fatto che word.firstLetter nel vero codice Scala assomiglia a:

 word(0) 

Scala considera le stringhe come una sequenza di Char, quindi se per qualche motivo volessi ottenere esplicitamente il primo carattere della stringa e farlo corrispondere, potresti usare qualcosa del genere:

 "Cat"(0).toString.matches("[a-cA-C]") res10: Boolean = true 

Non lo sto proponendo come il modo generale di fare la corrispondenza del modello regex, ma è in linea con l’approccio proposto per trovare prima il primo carattere di una stringa e poi confrontarlo con un’espressione regolare.

EDIT: Per essere chiari, il modo in cui vorrei farlo è, come altri hanno detto:

 "Cat".matches("^[a-cA-C].*") res14: Boolean = true 

Volevo solo mostrare un esempio il più vicino ansible al tuo pseudocodice iniziale. Saluti!

Per prima cosa dovremmo sapere che l’espressione regolare può essere usata separatamente. Ecco un esempio:

 import scala.util.matching.Regex val pattern = "Scala".r // <=> val pattern = new Regex("Scala") val str = "Scala is very cool" val result = pattern findFirstIn str result match { case Some(v) => println(v) case _ => } // output: Scala 

In secondo luogo, dovremmo notare che combinare l’espressione regolare con la corrispondenza di modelli sarebbe molto potente. Qui c’è un semplice esempio.

 val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r "2014-11-20" match { case date(year, month, day) => "hello" } // output: hello 

In effetti, la stessa espressione regolare è già molto potente; l’unica cosa che dobbiamo fare è renderla più potente da Scala. Ecco altri esempi in Scala Document: http://www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching.Regex