Showing posts with label raw strings. Show all posts
Showing posts with label raw strings. Show all posts

Thursday, October 1, 2009

Strings

This topic simply shows several things that can be done with strings. It is not exhaustive and focusses of things that cannot as easily be done with java strings.

Note: Because I am using Scala 2.7 we often need to use mkString to convert the processed string from a sequence of characters to a string. In scala 2.8 this is not required.

  1. /*
  2.    Making use of raw strings to create a multi line string
  3.    I add a | at the beginning of each line so that we can line up the quote nicely 
  4.    in source code then later strip it from the string using stripMargin
  5. */
  6. scala>val quote = """|I don-t consider myself a pessimist.                                                                                                
  7.      |                |I think of a pessimist as someone who is waiting for it to rain.
  8.      |                |And I feel soaked to the skin.
  9.      | 
  10.      |                |Leonard Cohen"""
  11. quote: java.lang.String = 
  12. |I don-t consider myself a pessimist. 
  13.                       |I think of a pessimist as someone who is waiting for it to rain.
  14.                       |And I feel soaked to the skin.
  15.        
  16.                       |Leonard Cohen
  17. // capilize the first character of each line
  18. scala>val capitalized = quote.lines.
  19.      |                         map( _.trim.capitalize).mkString("\n")
  20. capitalized: String = 
  21. |I don-t consider myself a pessimist.
  22. |I think of a pessimist as someone who is waiting for it to rain.
  23. |And I feel soaked to the skin.
  24. |Leonard Cohen
  25. // remove the margin of each line
  26. scala> quote.stripMargin        
  27. res1: String = 
  28. I don-t consider myself a pessimist. 
  29. I think of a pessimist as someone who is waiting for it to rain.
  30. And I feel soaked to the skin.
  31.        
  32. Leonard Cohen
  33. // this is silly.  I reverse the order of each word but keep the words in order
  34. scala> quote.stripMargin.         
  35.      |       lines.               
  36.      |       map( _.split(" ").   
  37.      |              map(_.reverse).
  38.      |              mkString (" ")).
  39.      |      mkString("\n")
  40. res16: String = 
  41. I t-nod redisnoc flesym a .tsimissep
  42. I kniht fo a tsimissep sa enoemos ohw si gnitiaw rof ti ot .niar
  43. dnA I leef dekaos ot eht .niks
  44. dranoeL nehoC
  45. scala>val myPatch = "-->This is my patch<--"                
  46. myPatch: java.lang.String = -->This is my patch<--
  47. // I replace the characters from point 10 in the string to myPatch.length 
  48. // (the full patch string)
  49. scala> quote.patch(10, myPatch, myPatch.length).mkString     
  50. res21: String = 
  51. |I don-t c-->This is my patch<--mist.
  52.                       |I think of a pessimist as someone who is waiting for it to rain.
  53.                       |And I feel soaked to the skin.
  54.        
  55.                       |Leonard Cohen
  56. // drop the first 3 lines of the string.  
  57. // there is also a take method
  58. scala> quote.lines.drop(3).mkString("\n").stripMargin 
  59. res25: String = 
  60.        
  61. Leonard Cohen
  62. // a bunch of examples of converting strings
  63. scala>"1024".toInt
  64. res26: Int = 1024
  65. scala>"1024".toFloat
  66. res27: Float = 1024.0
  67. scala>"1024".toDouble
  68. res28: Double = 1024.0
  69. scala>"1024".toLong  
  70. res29: Long = 1024
  71. scala>"102".toByte 
  72. res31: Byte = 102
  73. scala>"true".toBoolean
  74. res32: Boolean = true
  75. // format uses the java.util.Formatter class to format a string
  76. scala>"Hello %s,\nThe date is %2$tm %2$te,%2$tY".format("Jesse", new java.util.Date()) 
  77. res35: String = 
  78. Hello Jesse,
  79. The date is 09 30,2009
  80. /*
  81.    More silliness
  82.    I am replacing every other character with the character of the reversed string
  83.   
  84.    this is done by 
  85.    1. convert string to a list and zip it together with its reverse
  86.       We may still need to cover zipping.  It basically matches up the 
  87.       corresponding elements of two lists into one list
  88.       so 1,2,3 and one,two,three zipped would be (1,one),(2,two),(3,three)
  89.    2. Add an index to each element in the list with zipWithIndex
  90.    3. Use map to check if the element is an odd element using the index and return either the original element or the reversed element
  91.   
  92.    Not useful but interesting use of functional idioms
  93. */
  94. scala> quote.toList.                                          
  95.      |       zip(quote.reverse.toList).                       
  96.      |       zipWithIndex.                                    
  97.      |       map {                                            
  98.      |            case ((original,reversed),index) if(index % 2 == 0) => original
  99.      |            case ((original,reversed),index) => reversed                   
  100.      |           }.                                                              
  101.      |       mkString                                                            
  102. res42: String = |e oo -r noes|d r m s l     e s m s .        . i s e t o   e|a shlne  f anp|s i i t a   o e n   h  .siwrioi gifrrfig ioirwis.  h   n e o   a t i i s|pna f  enlhs a|e   o t e s i .        . s m s e     l s m r d|seon r- oo e|
  103. // filter out all non-vowels
  104. scala> quote.filter( "aeiou" contains _ ).mkString
  105. res51: String = ooieeaeiiioaeiiaoeoeoiaiioioaieeoaeoeieoaoe

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

Thursday, September 3, 2009

Adding methods using Traits

One useful application of a trait is the case where you want to add functionality to an existing class. In this example I have a class provided by a third party library (in this just a simple StringReader class from the Java library). But I want to be able to read lines as well as use the standard read methods.

One solution is to create a trait and when I instantiate the StringReader mix in the new trait. Code like new StringReader() with Lines results in a new class that extends StringReader and the trait Lines. As a result we have all the methods of StringReader and Lines. The biggest benefit is that we can define the trait to work with any Reader and then when we create the real instance we can mix it in to any class that extends Reader.

The other solution that can be used is to create an implicit conversion from StringReader to some other class. There are two draw backs here:
  • It is harder to tell what is happening
  • A trait can contain state but a "view" (which is what you get when one class is implicitly converted to another class) has no state it is just a view of the original class. In this example a view would work but in other examples like creating a pushback reader, it would not work.

Here is a simple example:

  1. scala>trait Lines {
  2.      | // the self type declares what type of class the trait can be applied to
  3.      | // if there is no self type then it is assumed it can be applied to Any type
  4.      | self:java.io.Reader =>
  5.      | def nextLine:Option[String] = {
  6.      | val builder = new scala.collection.mutable.StringBuilder()
  7.      |
  8.      | var next = read()
  9.      |
  10.      | while( next != -1 && next.toByte.toChar != '\n' ){
  11.      | builder += next.toByte.toChar
  12.      | next = read()
  13.      | }
  14.      |
  15.      | if( builder.isEmpty ) None
  16.      | else Some(builder.toString)
  17.      | }
  18.      | }
  19. defined trait Lines
  20. // Strings starting and ending with (""") are called raw strings.  All characters 
  21. // within """ """ are automatically escaped.
  22. // I am creating a reader and mixing in the Lines trait on construction
  23. scala>val reader = new java.io.StringReader( """line one
  24.      | line two"""with Lines
  25. reader: java.io.StringReader with Lines = $anon$1@3850620f
  26. scala> reader.nextLine
  27. res0: Option[String] = Some(line one)
  28. scala> reader.nextLine
  29. res1: Option[String] = Some(line two)
  30. scala> reader.nextLine
  31. res2: Option[String] = None
  32. scala> reader.nextLine
  33. res3: Option[String] = None
  34. // we can define a method that takes a reader with lines
  35. scala>def toCollection( reader:java.io.StringReader with Lines) = {
  36.      | def collect:List[String] = reader.nextLine match {
  37.      |   case None => Nil
  38.      |    // we do not need to worry about stack overflow
  39.      |    // because of tail recursion.  This method cannot be
  40.      |    // extended and collect is the last like in the collect
  41.      |    // method so this method will be transformed into a loop
  42.      |   case Some( line ) => line :: collect
  43.      | }
  44.      |
  45.      | collect
  46.      | }
  47. toCollection: (reader: java.io.StringReader with Lines)List[String]
  48. scala> toCollection( new java.io.StringReader( "line one\nlinetwo" ) with Lines).size
  49. res8: Int = 2