85

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?

asked Jun 11, 2010 at 9:54
1
  • I think "5" match { case Digit() => true case _ => false } looks better than using underlying pattern object. Commented Jan 31, 2017 at 13:20

6 Answers 6

72

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.

Nick H
11.5k1 gold badge39 silver badges49 bronze badges
answered Jun 11, 2010 at 13:59
6
  • 1
    I pimped with a function misses too. Match and missmatch :-) It's so annoying to have to write !s.matches(r) instead of s misses r. Hmm Commented Apr 5, 2012 at 12:38
  • 2
    How about the built-in "5" matches "\\d" which @polygenelubricants suggested? Commented Feb 16, 2014 at 21:17
  • 2
    Data matches a pattern, not vice-versa. The scaladoc on Regex makes a big deal about the lack of a boolean for "matches". Personally, I think you've swapped a nice match for a clunkier if-else. If you don't care about groups, use case r(_*) =>. Commented May 14, 2014 at 7:02
  • 1
    There has to be a way to do this without importing an external library... Commented Dec 22, 2017 at 22:38
  • 2
    @JameelaHuq Folks visiting this question will be pleased with 2.13, where Regex finally gets matches. github.com/scala/scala/pull/6521 Commented May 25, 2018 at 14:13
61

I don't know Scala all that well, but it looks like you can just do:

"5".matches("\\d")

References

answered Jun 11, 2010 at 10:46
5
  • 26
    Well, that works, but has the disadvantage that the pattern is compiled on every try to match. I'd like to avoid that for performance reasons. Commented Jun 11, 2010 at 10:57
  • 3
    @mkneissl: then it looks like your .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. Commented Jun 11, 2010 at 11:18
  • 4
    Thanks, that's what I am going to do, see my answer. I hope answering one's own questions is accepted behaviour on Stack Overflow... Meta says it is... Commented Jun 11, 2010 at 14:04
  • 2
    @ed. that's even slower and cruftier, so why? Commented Feb 16, 2014 at 21:20
  • 2
    The link given as a reference is broken Commented Apr 12, 2019 at 22:50
15

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
answered Jun 11, 2010 at 11:58
1
  • 5
    While true, the primary use of unapply and unapplySeq is implicitly in the cases of a match block. Commented Jun 11, 2010 at 15:06
12
 """\d""".r.unapplySeq("5").isDefined //> res1: Boolean = true
 """\d""".r.unapplySeq("a").isDefined //> res2: Boolean = false
answered Dec 18, 2012 at 6:49
4
  • Hmm. Why posting a duplicate of stackoverflow.com/a/3022478/158823 two years later? Commented Jan 16, 2013 at 19:26
  • 3
    Your original question asked for a result ending in 'true' or 'false', not 'Some' or 'None'. As far as I'm aware isDefined was not part of the library 2 years ago, but maybe it was. Anyway, my answer is not a duplicate ;-) Commented Jan 16, 2013 at 19:38
  • 1
    I see, it isn't a duplicate. Sorry. Commented Jan 16, 2013 at 20:41
  • 2
    No probs ;-) My mistake, I should have explained why I'm using isDefined in my answer. Just giving code as an answer is generally a bad idea, so it's my bad. Commented Jan 16, 2013 at 20:52
1

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

answered Aug 24, 2017 at 8:52
0

The answer is in the regex:

val Digit = """^\d$""".r

Then use the one of the existing methods.

answered Jun 12, 2010 at 17:13
6
  • 3
    I don't think anchors is the issue here. 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. Commented Jun 12, 2010 at 17:18
  • @polygenelubricants Well, 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. Commented Jun 14, 2010 at 13:32
  • Anchoring is not the problem. See also the "123" example in Vasil's answer. Commented Jun 14, 2010 at 18:15
  • 5
    @Daniel You might be missing the point -- My question was, if I only need to know if a regex matches fully, what is a good way to express that in Scala. There are a lot of working solutions, but in summary I think there is a method missing in Regex that just does that and nothing else. To answer the question in your commment: The difference from unapplySeq to findFirstMatch is, that I have to change the Regex to add the anchors. Both methods neither immediately express my intent nor return a boolean value, that is I'd have to go from Option to Boolean (no problem, but adding more clutter). Commented Jun 15, 2010 at 7:45
  • 1
    @mkneissl I dislike the concept of Java's matches, but ok. As for Option vs Boolean, add nonEmpty to the end and you'll get the Boolean. Commented Jun 15, 2010 at 12:33

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.