J'aimerais pouvoir trouver une correspondance entre la première lettre d'un mot et l'une des lettres d'un groupe tel que "ABC". En pseudo-code, cela pourrait ressembler à:
case Process(Word) =>
Word.firstLetter match {
case([a-c][A-C]) =>
case _ =>
}
}
Mais comment puis-je saisir la première lettre dans Scala au lieu de Java? Comment exprimer correctement l'expression régulière? Est-il possible de le faire dans une classe de cas ?
Vous pouvez le faire car les expressions régulières définissent des extracteurs, mais vous devez d’abord définir le motif regex. Je n'ai pas accès à un Scala REPL pour tester ceci mais quelque chose comme cela devrait marcher).
val Pattern = "([a-cA-C])".r
Word.firstLetter match {
case Pattern(c) => c bound to capture group here
case _ =>
}
Depuis la version 2.10, on peut utiliser la fonction d'interpolation de chaîne de 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
Encore mieux, vous pouvez lier des groupes d’expressions régulières:
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
Il est également possible de définir des mécanismes de liaison plus détaillés:
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 exemple impressionnant de ce qui est possible avec Dynamic
est présenté dans l'article de blog Introduction à Type Dynamic:
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")
}
}
Comme Delnan l'a fait remarquer, le mot clé match
dans Scala n'a rien à voir avec les expressions rationnelles. Pour savoir si une chaîne correspond à une expression rationnelle, vous pouvez utiliser le paramètre String.matches
méthode. Pour savoir si une chaîne commence par a, b ou c en minuscule ou en majuscule, la regex ressemblerait à ceci:
Word.matches("[a-cA-C].*")
Vous pouvez lire cette expression rationnelle comme "un des caractères a, b, c, a, b ou c suivi de rien" (.
signifie "n'importe quel caractère" et *
signifie "zéro fois ou plus", ainsi ". *" est une chaîne).
Pour développer un peu sur réponse d'Andrew : Le fait que les expressions régulières définissent des extracteurs peut être utilisé pour décomposer très gentiment les sous-chaînes mises en correspondance par la regex à l'aide du filtrage par motif de Scala, par exemple:
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.
}
String.matches est le moyen de faire une correspondance de motif au sens de regex.
Mais, mis à part, Word.firstLetter dans le code réel Scala) ressemble à ceci:
Word(0)
Scala considère les chaînes comme une séquence de caractères. Par conséquent, si, pour une raison quelconque, vous souhaitez explicitement obtenir le premier caractère de la chaîne et le faire correspondre, vous pouvez utiliser quelque chose comme celui-ci:
"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true
Je ne propose pas cela comme moyen général de faire une correspondance de motif regex, mais cela correspond à votre approche proposée pour trouver d'abord le premier caractère d'une chaîne, puis le faire correspondre à une regex.
EDIT: Pour être clair, voici comment je procéderais, comme d’autres l’ont dit:
"Cat".matches("^[a-cA-C].*")
res14: Boolean = true
Je voulais juste montrer un exemple aussi proche que possible de votre pseudocode initial. À votre santé!
Notez que l'approche de la réponse de @ AndrewMyers associe la chaîne entière à l'expression régulière, avec pour effet d'ancrer l'expression régulière aux deux extrémités de la chaîne à l'aide de ^
et $
. Exemple:
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
Et sans .*
à la fin:
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
Premièrement, nous devrions savoir que l'expression régulière peut être utilisée séparément. Voici un exemple:
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
Deuxièmement, nous devrions remarquer que combiner une expression régulière avec une correspondance de motif serait très puissant. Voici un exemple simple.
val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-11-20" match {
case date(year, month, day) => "hello"
} // output: hello
En fait, l'expression régulière elle-même est déjà très puissante. la seule chose à faire est de le rendre plus puissant avec Scala. Voici d'autres exemples dans Scala Document: http://www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching .Regex