Assume I have a Regex pattern I want to match many Strings to.
val Digit = """\d""".r
I just want to check whether a given String fully matches the Regex. What is a good and idiomatic way to do this in Scala?
I know that I can pattern match on Regexes, but this is syntactically not very pleasing in this case, because I have no groups to extract:
scala> "5" match { case Digit() => true case _ => false }
res4: Boolean = true
Or I could fall back to the underlying Java pattern:
scala> Digit.pattern.matcher("5").matches
res6: Boolean = true
which is not elegant, either.
Is there a better solution?
"5" match { case Digit() => true case _ => false }
looks better than using underlying pattern object.
Answering my own question I'll use the "pimp my library pattern"
object RegexUtils {
implicit class RichRegex(val underlying: Regex) extends AnyVal {
def matches(s: String) = underlying.pattern.matcher(s).matches
}
}
and use it like this
import RegexUtils._
val Digit = """\d""".r
if (Digit matches "5") println("match")
else println("no match")
unless someone comes up with a better (standard) solution.
Notes
I didn't pimp String to limit the scope of potential side effects.
unapplySeq does not read very well in that context.
I don't know Scala all that well, but it looks like you can just do:
"5".matches("\\d")
References
http://langref.org/scala/pattern-matching/matching
.pattern.matcher(text).matches
is the way to go. You can hide the verbosity under some utility method or overloaded operator or something if Scala supports it.
For the full match you may use unapplySeq. This method tries to match target (whole match) and returns the matches.
scala> val Digit = """\d""".r
Digit: scala.util.matching.Regex = \d
scala> Digit unapplySeq "1"
res9: Option[List[String]] = Some(List())
scala> Digit unapplySeq "123"
res10: Option[List[String]] = None
scala> Digit unapplySeq "string"
res11: Option[List[String]] = None
case
s of a match
block.
"""\d""".r.unapplySeq("5").isDefined //> res1: Boolean = true
"""\d""".r.unapplySeq("a").isDefined //> res2: Boolean = false
The answer is in the regex:
val Digit = """^\d$""".r
Then use the one of the existing methods.
String/Pattern/Matcher.matches
, in Java at least, is whole string match already. I think the issue is just style/idiom for regex-ing in Scala, i.e. what those "one of the existing methods" are.
Matcher.matches
is an aberration. Ok, it makes some optimizations possible, though I don't know if the Java library actually takes advantage of it. But the standard way for Regular Expressions to express that a full match is required is to use anchors. Since the Scala library does not provide a full match method, then the proper way to do it is to use anchors. Either that, or use the Java library.
matches
, but ok. As for Option
vs Boolean
, add nonEmpty
to the end and you'll get the Boolean
.
Using Standard Scala library and a pre-compiled regex pattern and pattern matching (which is scala state of the art):
val digit = """(\d)""".r
"2" match {
case digit( a) => println(a + " is Digit")
case _ => println("it is something else")
}
more to read: http://www.scala-lang.org/api/2.12.1/scala/util/matching/index.html
Success story sharing
misses
too. Match and missmatch :-) It's so annoying to have to write!s.matches(r)
instead ofs misses r
. Hmm"5" matches "\\d"
which @polygenelubricants suggested?case r(_*) =>
.