Reputation: 8195
This bit of code implements a mini string matching language - which understands two symbols (?=match any char, *=match one or more char). This code seems to work just fine, but it seems a little bit inelegant.
object Re {
def check(search: String, input: String):Boolean = {
search match {
case `input` => true
case x if x.startsWith("?") =>
check(x.stripPrefix("?"), input.tail)
case x if x.startsWith("*") => input match {
case "" => false
case i => check(x.stripPrefix("*"), i.tail) | check(x, i.tail)
}
case _ => false
}
}
}
Specifically, I dislike the cases where I say x if x.startswith(something) and then have to strip that something.
Does scala have a more idiomatic way to do this? Something along the lines of how the Seq matcher works so that I don't need startsWith or stripPrefix.
Upvotes: 2
Views: 236
Reputation: 1986
No to my best knowledge. So i would rather stick to sequences pattern matching:
def check(search: String, input: String): Boolean = check(search.toList, input.toList)
def check(search: List[Char], input: List[Char]): Boolean = {
search match {
case _ if search == `input` => true
case '?' :: tail => check(tail, input.tail)
case '*' :: tail => if (input.isEmpty) false else check(tail, input.tail) | check(search, input.tail)
case _ => false
}
}
It might be not so elegant solution as in @0__ answer but in case this function is going to change in the future IMO it would be better to have capabilities of sequence pattern matching.
Hope it helps!
Upvotes: 2
Reputation: 67280
It would be great if +:
worked as extractor, but unfortunately the type conversion fails:
val head +: tail = "hello"
<console>:54: error: scrutinee is incompatible with pattern type;
found : Coll with scala.collection.SeqLike[T,Coll]
required: String
val head +: tail = "hello"
^
But you could define an analogous extractor:
object ~> {
def unapply(s: String): Option[(Char, String)] =
if (s.isEmpty) None else Some((s.charAt(0), s.substring(1)))
}
def check(search: String, input: String): Boolean = (search, input) match {
case (`input`, _) => true
case ('?' ~> stail, _ ~> itail) => check(stail, itail)
case ('*' ~> stail, _ ~> itail) => check(stail, itail) || check(search, itail)
case _ => false
}
assert(!check("gaga", "baba"))
assert( check("gaga", "gaga"))
assert(!check("?gaga", "gaga"))
assert( check("?gaga", "Xgaga"))
assert(!check("?gaga", "XYgaga"))
assert( check("*gaga", "Xgaga"))
assert( check("*gaga", "XYgaga"))
assert(!check("*gaga", "gaga"))
Upvotes: 6