Showing posts with label MatchError. Show all posts
Showing posts with label MatchError. Show all posts

Monday, January 11, 2010

Regular Expression 3: Regex matching

This post covers basically the same things as Matching Regular Expressions but goes into a bit more detail. I recommend reading both posts since there is unique information in each.

The primary new item I show here is that more advanced matching techniques can be used but more importantly all groups are matched even groups that are within another group.

Note: The examples use Scala 2.8. Most examples will work with 2.7 but I believe the last example is Scala 2.8 only.

  1. scala> val date = "11/01/2010"
  2. date: java.lang.String = 11/01/2010
  3. scala> val Date = """(\d\d)/(\d\d)/(\d\d\d\d)""".r
  4. Date: scala.util.matching.Regex = (\d\d)/(\d\d)/(\d\d\d\d)
  5. /*
  6. When a Regex object is used in matching each group is assigned to a variable
  7. */
  8. scala> val Date(day, month, year) = date          
  9. day: String = 11
  10. month: String = 01
  11. year: String = 2010
  12. scala> val Date = """(\d\d)/((\d\d)/(\d\d\d\d))""".r
  13. Date: scala.util.matching.Regex = (\d\d)/((\d\d)/(\d\d\d\d))
  14. /*
  15. This example demonstates how all groups must be assigned, if not there will be a matchError thrown
  16. */
  17. scala> val Date(day, monthYear, month, year) = date
  18. day: String = 11
  19. monthYear: String = 01/2010
  20. month: String = 01
  21. year: String = 2010
  22. scala> val Date(day, month, year) = date           
  23. scala.MatchError: 11/01/2010
  24. at .< init>(< console>:5)
  25. at .< clinit>(< console>)
  26. // but placeholders work in Regex matching as well:
  27. scala> val Date(day, _, month, year) = date
  28. day: String = 11
  29. month: String = 01
  30. year: String = 2010
  31. scala> val Names = """(\S+) (\S*)""".r             
  32. Names: scala.util.matching.Regex = (\S+) (\S*)
  33. scala> val Names(first, second) = "Jesse Eichar"
  34. first: String = Jesse
  35. second: String = Eichar
  36. /*
  37. If you want to use Regex's in assignment you must be sure the match will work.  Otherwise you should do real matching
  38. */
  39. scala> val Names(first, second) = "Jesse"       
  40. scala.MatchError: Jesse
  41. at .< init>(< console>:5)
  42. at .< clinit>(< console>)
  43. scala> val M = """\d{3}""".r
  44. M: scala.util.matching.Regex = \d{3}
  45. /*
  46. There must be a group in the Regex or match will fail
  47. */
  48. scala> val M(m) = "Jan"
  49. scala.MatchError: Jan
  50. at .< init>(< console>:5)
  51. at .< clinit>(< console>)

The following are a few more complex examples
  1. scala> val Date = """((\d\d)/(\d\d)/(\d{4}))|((\w{3}) (\d\d),\s?(\d{4}))""".r         
  2. Date: scala.util.matching.Regex = ((\d\d)/(\d\d)/(\d{4}))|((\w{3}) (\d\d),\s?(\d{4}))
  3. /*
  4. The Regex has an or in it.  So only 1/2 of the groups will be non-null.
  5. If the first group is a String then it is non-null and the next three elements
  6. the pattern will be day/month/year
  7. Otherwise if the 5th group is a String then the patter will be month day, year
  8. Lastly a catch all
  9. */
  10. scala> def printDate(date:String) = date match {                                      
  11.      | case Date(_:String,day,month,year,_,_,_,_) => (day,month,year)                 
  12.      | case Date(_,_,_,_,_:String,month,day,year) => (day,month,year) // process month
  13.      | case _ => ("x","x","x")                                                        
  14.      | }
  15. printDate: (date: String)(StringStringString)
  16. scala> printDate("Jan 01,2010"
  17. res0: (StringStringString) = (01,Jan,2010)
  18. scala> printDate("01/01/2010"
  19. res1: (StringStringString) = (01,01,2010)
  20. /*
  21. A silly example which drops the first element of the date string
  22. not useful but this demonstrates that we are matching agains a sequence so 
  23. the _* can be used to match the rest of the groups
  24. */
  25. scala> def split(date:String) = date match {         
  26.      | case d @ Date(_:String ,_*) => d drop 3       
  27.      | case d @ Date(_,_,_,_,_:String,_*) => d drop 4
  28.      | case _ => "boom"                              
  29.      | }
  30. split: (date: String)String
  31. scala> split ("Jan 31,2004")
  32. res5: String = 31,2004
  33. scala> split ("11/12/2004"
  34. res6: String = 12/2004
  35. /*
  36. This is just a reminder that the findAllIn returns an iterator which (since it is probably a short iterator) can be converted to a sequence and processed with matching
  37. */
  38. scala> val Seq(one,two,_*) = ("""\d\d/""".r findAllIn "11/01/2010" ).toSeq  
  39. one: String = 11/
  40. two: String = 01/
  41. scala> val Seq(one,two) = ("""\d\d/""".r findAllIn "11/01/2010" ).toSeq   
  42. one: String = 11/
  43. two: String = 01/
  44. // drop the two first matches and assign the rest to d
  45. scala> val Seq(_,_,d @ _*) = ("""\d\d/""".r findAllIn "11/01/20/10/" ).toSeq
  46. d: Seq[String] = ArrayBuffer(20/, 10/)

Tuesday, November 17, 2009

XML matching

The Scala XML support includes the ability to match on XML elements. Here are several examples. One of the most important parts to remember is to not miss the '{' and '}'.

  1. scala> <document>
  2.      |  <child1/>
  3.      |  <child2/>
  4.      | </document>
  5. res0: scala.xml.Elem =
  6. <document>
  7.         <child1></child1>
  8.         <child2></child2>
  9.        </document>
  10. scala> res0 match {
  11.        // match the document tag
  12.        // the {_*} is critical
  13.      | case <document>{_*}</document> => println("found document element")
  14.      | case _ => println("Found another element")
  15.      | }
  16. found document element
  17. scala> res0 match {
  18.        // assign the document element to e
  19.      | case e @ <document>{_*}</document> => println(e)
  20.      | case _ => println("Found another element")
  21.      | }
  22. <document>
  23.         <child1></child1>
  24.         <child2></child2>
  25.        </document>
  26. scala> res0 match {
  27.        // assign the children of document to children
  28.        // notice that there are Text elements that are part of children
  29.      | case <document>{children @ _*}</document> => println(children)
  30.      | case _ => println("Found another element")
  31.      | }
  32. ArrayBuffer(
  33.         , <child1></child1>,
  34.         , <child2></child2>,
  35.        )
  36. // the '\' is xpath like but only returns elements and attributes
  37. // in this case the \ "_" returns all element children of res0.  It
  38. // will not return the Text elements.
  39. scala> res0 \ "_" foreach {
  40.      | case <child1>{_*}</child1> => println("child1 found")
  41.      | case <child2>{_*}</child2> => println("child2 found")
  42.      | case e => println("found another element")
  43.      | }
  44. child1 found
  45. child2 found
  46. // another example of how \ does not return any text elements.  This returns
  47. // no elements
  48. scala> <doc>Hello</doc> \ "_" foreach { case scala.xml.Text(t) => println("a text element found: "+t) }
  49. // the .child returns all children of an Elem
  50. scala> <doc>Hello</doc>.child foreach { case scala.xml.Text(t) => println("a text element found: "+t) }
  51. a text element found: Hello
  52. // This example throws a match error because there are whitespace text elements
  53. // that cause the match to fail.
  54. scala> res0 match {                                                                                    
  55.      | case <document><child1/><child2/></document> => println("found the fragment")
  56.      | }
  57. scala.MatchError: <document>
  58.         <child1></child1>
  59.         <child2></child2>
  60.        </document>
  61.        at .< init>(< console>:6)
  62.        at .< clinit>(< console>)
  63.        at RequestResult$.< init>(< console>:3)
  64.        at RequestResult$.< clinit>(< console>)
  65.        at RequestResult$result(< console>)
  66.        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  67.        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMetho...
  68. // The trim method removes the whitespace nodes so now the 
  69. // match will work
  70. scala> scala.xml.Utility.trim(res0) match {                                                            
  71.      | case <document><child1/><child2/></document> => println("found the fragment")
  72.      | }
  73. found the fragment
  74. // you can select part of the tree using matching
  75. // child2 is assigned to 3 in this example.
  76. scala> scala.xml.Utility.trim(res0) match {                                           
  77.      | case <document><child1/>{e @ _*}</document> => println("found the fragment:"+e)
  78.      | }
  79. found the fragment:RandomAccessSeq(<child2></child2>)

Wednesday, September 16, 2009

Matching Regular expressions

This topic is derived from the blog post: Using pattern matching with regular expressions in Scala

The Regex class in Scala provides a very handy feature that allows you to match against regular expressions. This makes dealing with certain types of regular expression very clean and easy to follow.

What needs to be done is to create a Regex class and assign it to a val. It is recommended that the val starts with an Uppercase letter, see the topic of matching about the assumptions matching makes based on the first letter of the Match case clause.

There is nothing like examples to help explain an idea:
  1. // I normally use raw strings (""") for regular expressions so that I don't have to escape all \ characters
  2. // There are two ways to create Regex objects.
  3. // 1. Use the RichString's r method
  4. // 2. Create it using the normal Regex constructor
  5. scala> val Name = """(\w+)\s+(\w+)""".r
  6. Name: scala.util.matching.Regex = (\w+)\s+(\w+)
  7. scala> import scala.util.matching._
  8. import scala.util.matching._
  9. // Notice the val name starts with an upper case letter
  10. scala> val Name = new Regex("""(\w+)\s+(\w+)""")
  11. Name: scala.util.matching.Regex = (\w+)\s+(\w+)
  12. scala> "Jesse Eichar"match {
  13.      | case Name(first,last) => println("found: ", first, last)
  14.      | case _ => println("oh no!")
  15.      | }
  16. (found: ,Jesse,Eichar)
  17. scala> val FullName = """(\w+)\s+(\w+)\s+(\w+)""".r
  18. FullName: scala.util.matching.Regex = (\w+)\s+(\w+)\s+(\w+)
  19. // If you KNOW that the match will work you can assign it to a variable
  20. // Only do this if you are sure the match will work otherwise you will get a MatchError
  21. scala> val FullName(first, middle, last) = "Jesse Dale Eichar"
  22. first: String = Jesse
  23. middle: String = Dale
  24. last: String = Eichar

Tuesday, August 4, 2009

Basic Matching

Matching is a powerful concept in scala that is similar to a switch in Java. The difference is that matching takes it to another level. We will start with basic switching in this entry.

Note. If a match is not found a scala.MatchError is thrown
  1. scala>val s = "sampleString"
  2. s: java.lang.String = sampleString
  3. scala> s match {
  4.      | case"sampleString" => "its a match!"
  5.      | case _ => "no match"
  6.      | }
  7. res0: java.lang.String = its a match!
  8. scala> s match {
  9.      | case m @"sampleString" => "its a match!"
  10.      | case _ => "no match"
  11.      | }
  12. res1: java.lang.String = its a match!
  13. scala> s match {
  14.      | case m @"sampleString" => "we found "+m+"!"
  15.      | case _ => "no match"
  16.      | }
  17. res2: java.lang.String = we found sampleString!
  18. scala>  s match {
  19.      | case m if(m.startsWith("s") ) => "its a match!"
  20.      | case _ => "no match"
  21.      | }
  22. res3: java.lang.String = its a match!
  23. scala>  s match {
  24.      | case m => "this matches everything"
  25.      | }
  26. res4: java.lang.String = this matches everything
  27. scala>val obj:Any = s // I am assigning s to a variable whose type is Any (parent of all object).
  28. obj: Any = sampleString
  29. scala>  obj match {
  30.      | case string:String => "we found a string"
  31.      | case integer:Int => "we found an integer"
  32.      | case _ => "hmmm don't know what it is"
  33.      | }
  34. res6: java.lang.String = we found a string
  35. scala>// Now  we will see what happens when a match fails
  36. scala>  obj match {
  37.      | case integer:Int => "we found an integer"
  38.      | case double:Double => "we found an double"
  39.      | }
  40. scala.MatchError: sampleString
  41.                   at .(:7)
  42.                   at .()
  43.                   at RequestResult$.(:3)
  44.                   at RequestResult$.()
  45.                   at RequestResult$result()
  46.                   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  47.                   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  48.                   at sun.reflect.DelegatingMethodAccessorImpl.i...
  49. scala>