Wednesday, February 3, 2010

Regex ReplaceAllIn

Note: Updated on Feb 13th for the newer API on Scala 2.8 trunk. (This is life on the bleeding edge, thanks Daniel).

A couple new methods have just been added to Scala 2.8 Regex. You will need to download a version of Scala 2.8 more recent than Scala2.8-Beta1.

The methods are related to replacing text using a regular expression and to say they are useful is an understatement. Lets take a look:
  1. scala> val quote = """I don't like to commit myself about heaven and hell - you see, I have friends in both places. 
  2.      | Mark Twain"""                                                                                                
  3. quote: java.lang.String = 
  4. I don't like to commit myself about heaven and hell - you see, I have friends in both places. 
  5. Mark Twain
  6. scala> val expr = "e".r    
  7. expr: scala.util.matching.Regex = e
  8. /* 
  9. This first method is not new or is it interesting.  But the new methods are both related
  10. so lets start with the basic form of replaceAllIn
  11. */
  12. scala> expr.replaceAllIn(quote, "**")
  13. res1: String = 
  14. I don't lik** to commit mys**lf about h**av**n and h**ll - you s****, I hav** fri**nds in both plac**s. 
  15. Mark Twain
  16. // this does the same thing
  17. scala> quote.replaceAll("e","**")
  18. res2: java.lang.String = 
  19. I don't lik** to commit mys**lf about h**av**n and h**ll - you s****, I hav** fri**nds in both plac**s. 
  20. Mark Twain
  21. /*
  22. Now things get interesting.  Using this form of replaceAllIn we can determine the replacement on a case by case basis.
  23. It provides the Match object as the parameter so you have complete access to all 
  24. the matched groups, the location of the match etc...
  25. The method takes a Match => String function.  Very, very powerful.
  26. */
  27. scala> expr.replaceAllIn(quote, s => if(util.Random.nextBoolean) "?" else "*")
  28. res5: String = 
  29. I don't lik? to commit mys?lf about h?av?n and h?ll - you s*?, I hav? fri*nds in both plac*s. 
  30. Mark Twain
  31. /*
  32. Another example using some of the matcher functionality
  33. */
  34. scala> expr.replaceAllIn(quote, m => m.start.toString)                        
  35. res6: String = 
  36. I don't lik11 to commit mys26lf about h37av40n and h48ll - you s5960, I hav68 fri73nds in both plac90s. 
  37. Mark Twain
  38. /*
  39. Another crazy useful method is the replaceSomeIn.  It is similar to the replaceAllIn that takes a function except that the function in replaceSomeIn returns an Option.  If None then there is no replacement.  Otherwise a replacement is performed.  Very nice when dealing with complex regular expressions.
  40. In this example we are replacing all 'e's start are before the 50th character in the string with -
  41. */
  42. scala> expr.replaceSomeIn(quote, m => if(m.start > 50) None else Some("-"))
  43. res3: String = 
  44. I don't lik- to commit mys-lf about h-av-n and h-ll - you see, I have friends in both places.
  45. Mark Twain


  1. The String => String replaceAllIn has been removed. The replaceAllMatchesIn method has been renamed replaceAllIn. And there's now an replaceSomeIn, which takes a Match => Option[String]. Much happyness, but you might want to change the blog. :-)

  2. Done. Thanks for noticing this. And I agree replaceSomeIn is a welcome addition