Scala for the Impatient
.pdf108 |
Chapter 9 |
Files and Regular Expressions |
|
You can also redirect input from a URL:
"grep Scala" #< new URL("http://horstmann.com/index.html") !
You can combine processes with p #&& q (execute q if p was successful) and p #|| q (execute q if p was unsuccessful). But frankly, Scala is better at control flow than the shell, so why not implement the control flow in Scala?
NOTE: The process library uses the familiar shell operators | > >> < && ||, but it prefixes them with a # so that they all have the same precedence.
If you need to run a process in a different directory, or with different environment variables, construct the ProcessBuilder with the apply method of the Process object. Supply the command, the starting directory, and a sequence of (name, value) pairs for environment settings.
val p = Process(cmd, new File(dirName), ("LANG", "en_US"))
Then execute it with the ! operator:
"echo 42" #| p !
9.10 Regular Expressions
When you process input, you often want to use regular expressions to analyze it. The scala.util.matching.Regex class makes this simple. To construct a Regex object, use the r method of the String class:
val numPattern = "[0-9]+".r
If the regular expression contains backslashes or quotation marks, then it is a good idea to use the “raw” string syntax, """...""". For example:
val wsnumwsPattern = """\s+[0-9]+\s+""".r
// A bit easier to read than "\\s+[0-9]+\\s+".r
The findAllIn method returns an iterator through all matches. You can use it in a for loop:
for (matchString <- numPattern.findAllIn("99 bottles, 98 bottles")) process matchString
or turn the iterator into an array:
val matches = numPattern.findAllIn("99 bottles, 98 bottles").toArray // Array(99, 98)
To find the first match anywhere in a string, use findFirstIn. You get an Option[String]. (See Chapter 14 for the Option class.)
Exercises 109
val m1 = wsnumwsPattern.findFirstIn("99 bottles, 98 bottles") // Some(" 98 ")
To check whether the beginning of a string matches, use findPrefixOf:
numPattern.findPrefixOf("99 bottles, 98 bottles") // Some(99)
wsnumwsPattern.findPrefixOf("99 bottles, 98 bottles") // None
You can replace the first match, or all matches:
numPattern.replaceFirstIn("99 bottles, 98 bottles", "XX")
//"XX bottles, 98 bottles" numPattern.replaceAllIn("99 bottles, 98 bottles", "XX")
//"XX bottles, XX bottles"
9.11Regular Expression Groups
Groups are useful to get subexpressions of regular expressions. Add parentheses around the subexpressions that you want to extract, for example:
val numitemPattern = "([0-9]+) ([a-z]+)".r
To match the groups, use the regular expression object as an “extractor” (see Chapter 14), like this:
val numitemPattern(num, item) = "99 bottles" // Sets num to "99", item to "bottles"
If you want to extract groups from multiple matches, use a for statement like this:
for (numitemPattern(num, item) <- numitemPattern.findAllIn("99 bottles, 98 bottles")) process num and item
Exercises
1.Write a Scala code snippet that reverses the lines in a file (making the last line the first one, and so on).
2.Write a Scala program that reads a file with tabs, replaces each tab with spaces so that tab stops are at n-column boundaries, and writes the result to the same file.
3.Write a Scala code snippet that reads a file and prints all words with more than 12 characters to the console. Extra credit if you can do this in a single line.
110Chapter 9 Files and Regular Expressions
4.Write a Scala program that reads a text file containing only floating-point numbers. Print the sum, average, maximum, and minimum of the numbers in the file.
5.Write a Scala program that writes the powers of 2 and their reciprocals to a file, with the exponent ranging from 0 to 20. Line up the columns:
11
20.5
4 0.25
... ...
6.Make a regular expression searching for quoted strings "like this, maybe with \" or \\" in a Java or C++ program. Write a Scala program that prints out all such strings in a source file.
7.Write a Scala program that reads a text file and prints all tokens in the file that are not floating-point numbers. Use a regular expression.
8.Write a Scala program that prints the src attributes of all img tags of a web page. Use regular expressions and groups.
9.Write a Scala program that counts how many files with .class extension are in a given directory and its subdirectories.
10.Expand the example with the serializable Person class that stores a collection of friends. Construct a few Person objects, make some of them friends of another, and then save an Array[Person] to a file. Read the array back in and verify that the friend relations are intact.