Skip to content

Instantly share code, notes, and snippets.

@debasishg
Created May 13, 2013 10:08
Show Gist options
  • Save debasishg/5567328 to your computer and use it in GitHub Desktop.
Save debasishg/5567328 to your computer and use it in GitHub Desktop.
regex interpolation fails ..
Apples-MacBook-Pro:~ debasishg$ scala
Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
implicit class RContext(sc: StringContext) {
def r =
new util.matching.Regex(
sc.parts.mkString(""),
sc.parts.tail.map(_ => "x"): _*)
}
// Exiting paste mode, now interpreting.
defined class RContext
scala> "database:[table1,table2]" matches """(\w+)(:\[(\w+)(,(\w+))*\])?"""
res0: Boolean = true
scala> :paste
// Entering paste mode (ctrl-D to finish)
"database:[table1,table2]" match {
case r"""(\w+)(:\[(\w+)(,(\w+))*\])?""" => true
case _ => false
}
// Exiting paste mode, now interpreting.
res1: Boolean = false
scala>
@igstan
Copy link

igstan commented May 13, 2013

Your r method should be an extractor object in order to work with match expressions. This is incomplete, but proves the point:

scala> implicit class RContext(sc: StringContext) {
     |   object r {
     |     def apply(args: Any*) =
     |       sc.parts.mkString.r
     | 
     |     def unapplySeq(s: String): Option[Seq[String]] =
     |       sc.parts.mkString.r.unapplySeq(s)
     |   }
     | }
defined class RContext

scala> "database:[table1,table2]" matches """(\w+)(:\[(\w+)(,(\w+))*\])?"""
res25: Boolean = true

scala> "database:[table1,table2]" match {
     |   case r"""(?:\w+)(?::\[(?:\w+)(?:,(?:\w+))*\])?""" => true
     |   case _ => false
     | }
res26: Boolean = true

scala> val pattern = r"""(\w+)(:\[(\w+)(,(\w+))*\])?"""
pattern: scala.util.matching.Regex = (\w+)(:\[(\w+)(,(\w+))*\])?

scala> val pattern(a,b,c,d,e) = "database:[table1,table2]"
a: String = database
b: String = :[table1,table2]
c: String = table1
d: String = ,table2
e: String = table2

scala> 

Notice however that the pattern in the match expressions uses only non-capturing groups, otherwise it wouldn't match. It's possible to extend the extractor to bind named groups to variables, but I'm not sure it's trivial. This friend of mine has achieved something along these lines here:

https://github.com/alexandru/shifter/blob/master/web-api/src/main/scala/shifter/web/api/mvc/PathMatcher.scala
https://github.com/alexandru/shifter/blob/master/web-api/src/test/scala/shifter/web/api/mvc/PathMatcherSuite.scala

@igstan
Copy link

igstan commented May 13, 2013

Here's also a blog post that gets into some of the details: http://hootenannylas.blogspot.ro/2013/02/pattern-matching-with-string.html

@igstan
Copy link

igstan commented May 13, 2013

Okay, so your original version works just fine with non-capturing groups. That was the problem.

@debasishg
Copy link
Author

this works ..

scala> :paste
// Entering paste mode (ctrl-D to finish)

"database:[table1,table2]" match {
  case r"""(\w+)$d(:\[(\w+)$f(,(\w+)$x)*$y\])?$t""" => (d, f, x, y, t)
  case _ => "no match"
}

// Exiting paste mode, now interpreting.

res29: java.io.Serializable = (database,:[table1,table2],table1,,table2,table2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment