Regex chaining

746 views
Skip to first unread message

Ilkka Huotari

unread,
Mar 22, 2011, 12:41:46 PM3/22/11
to scala...@googlegroups.com
Hi,

I fairly new to Scala and I'm trying to use regexps for the first time.

I noticed that when in Java I do this: string.replace(regex, "replacement"), in Scala I do this: regex.replace(string, "replacement").

Now, I have two regexps defined which I use throughout the code, and sometimes I use only one, sometimes I use both, and earlier used to chain them together like this: string.replace(regex1, "1").replace(regex2, "2"). 

Now in Scala, it seems that I have to do it like this:
regex2.replace(regex1.replace(string, "1"), "2")

IMO, the second way is quite difficult to read/write and understand. Is it still the way it is supposed to be done in Scala?

Thanks,
Ilkka

Lex

unread,
Mar 22, 2011, 12:52:17 PM3/22/11
to scala...@googlegroups.com, Ilkka Huotari
Have you tried string.replace(regex, "replacement") in Scala?

Ilkka Huotari

unread,
Mar 22, 2011, 1:16:40 PM3/22/11
to scala...@googlegroups.com, Ilkka Huotari, Lex
Hmm, I went to Scala style so that I could use """regex""" way and I wouldn't have to escape things in double backslash. But now that I think of it more, I think I can use """...""" way with Java pattern as well.

Also, I think I could solve a lot of the awkwardness by wrapping all those replace methods in some other object. So, it seems there are ways to solve this issue.


Daniel Sobral

unread,
Mar 22, 2011, 2:18:42 PM3/22/11
to scala...@googlegroups.com, Ilkka Huotari
I personally dislike Scala's Regex. However, I haven't ever been able to come up with something truly superior -- aside from one or two minor suggestions that have been incorporated in the library.

So, I'll present two ways to do this using Scala's regex, but, first, I'll like to just mention that Scala's String is Java's String, so any method present in Java is present in Scala, as far as strings are concerned. So, if your use case is easily solved by chaining ".replace", then, by all means, go for it.

So, if one wants to explore Scala options to handle this, the first way is to convert the regex into a replacing function:

val f1 = "a".r replaceAllIn (_: String, "1")
val f2 = "b".r replaceAllIn (_: String, "2")
val f3 = f1 andThen f2
f3("aabbabab")

The second way is to take advantage of Scala's ability to accept closures for replacement:

import scala.util.matching.Regex.Match
def f = "[ab]".r replaceSomeIn ( _: String, {
  case Match("a") => Some("1")
  case Match("b") => Some("2")
  case _ => None } )
f("aabbXabab")

This later example works better if things are really dynamic. You could, then do stuff like this:

type Matcher = PartialFunction[Match, String]
implicit def toMakeMatcher(pattern: String) = new { def makeMatcher(pf: Matcher) = (pattern, pf) }
def replacer(replacements: (String, Matcher)*) = {
  val (patterns, matchers) = replacements.unzip
  (patterns mkString "|").r replaceSomeIn (_: String, matchers reduceLeft (_ orElse _) lift)
}

val f1 = "a" makeMatcher { case Match("a") => "1" }
val f2 = "b" makeMatcher { case Match("b") => "2" }
val f3 = replacer(f1, f2)
f3("aabbXabab")

Or even,

implicit def toReplacer(pattern: String) = new { def replaceWith(replacement: String): (String, Matcher) = { val regex = pattern.r; (pattern, { case regex() => replacement }) } }
val f4 = "a" replaceWith "1"
val f5 = "b" replaceWith "2"
val f6 = replacer(f4, f5)
f6("aabbXabab")

So, there's your thought snack for today. :-)
--
Daniel C. Sobral

I travel to the future all the time.
Reply all
Reply to author
Forward
0 new messages