美文网首页
快学Scala第9章----文件和正则表达式

快学Scala第9章----文件和正则表达式

作者: 胡杨1015 | 来源:发表于2016-06-21 23:42 被阅读0次

    本章要点

    • Source.fromFile(...).getLines.toArray 输出文件文件的所有行
    • Source.fromFile(...).mkString 以字符串形式输出文件内容
    • 将字符串转换为数字,可以用toInt或toDouble方法
    • 使用Java的PrintWriter来写入文本文件- “正则”.r 是一个Regex对象
    • 如果你的正则表达式包含反斜杠或引号的话,用"""..."""
    • 如果正则模式包含分组,你可以使用如下语法来提取它们的内容 for (regex(变量1, ..., 变量n) <- 字符串)

    读取行

    使用scala.io.Source 对象的getLines方法

    import scala.io.Source
    val source = Source.fromFile("myfile.txt", "UTF-8")
    val lineIterator = source.getLines
    for (line <- lineIterator) println(line)
    
    // 或者将这些行放到数组或数组缓冲
    val lines = source.getLines.toArray
    
    // 使用完毕后关闭Source对象
    source.close
    

    读取字符

    直接把source对象当做迭代器来从文件中读取单个字符:

    for (c <- source)  处理c
    

    source对象的buffered方法可以获得一个BufferedIterator[A]迭代器,使用它的head方法可以查看下一个字符,但不会把它当做以处理的字符:

    import scala.io.Source
    val source = Source.fromFile("myfile.txt", "UTF-8")
    val iter = source.buffered
    while (iter.hasNext) {
        if (iter.head 是符合预期的) {
            处理 iter.next
        } else {
             iter.next
             ...
        }
    }
    
    source.close
    

    注意: 在else分之必须有iter.next或者while循环中有跳出循环的语句,否则将很可能陷入死循环。
    如果文件不大,也可以读取成字符串处理:

    val contents = source.mkString
    

    读取词法单元和数字

    val tokens = source.mkString.split("\\s+")  // 以空格隔开的词法单元
    
    // 转换成Double类型
    val numbers = for (w <- tokens) yield w.toDouble
    // 或者
    val numbers = tokens.map(_.toDouble)
    

    从控制台读取数字

    print ("How old are you? ")
    val age = readInt()  // readLong or readDouble  这种方法假定了下一行输入只包含单个数字,
                                 // 且前后没有空格,否则会抛出异常:NumberFormatException
    

    从URL或其他源读取

    val source1 = Source.fromURL("http://horstamnn.com", "UTF-8")
    val source2 = Source.fromString("Hello, World")
    val source3 = Source.stdin
    ...
    source1.close
    source2.close
    source3.close
    

    读取二进制文件

    Scala没有提供读取二进制文件的方法,需要使用Java的类库

    val file = new File(filename)
    val in = new FileInputStream(file)
    val bytes = new Array[Byte] (file.length.toInt)
    in.read(bytes)
    in.close
    

    写入文本文件

    Scala同样没有内建的对写入文件的支持,需要使用java.io.PrintWriter:

    val out = new PrintWriter("numbter.txt")
    for (i <- 1 to 100) out.println(i)
    out.close
    

    PrintWrite的printf方法比较特殊,需要你将参数转换成AnyRef才可以:

    out.printf("%6d %10.2f", quantity.asInstanceOf[AnyRef], price.asInstanceOf[AnyRef])
    
    // 为了避免这个麻烦,可以使用String类的format方法:
    out.print("%6d %10.2f".format(quantity, price))
    

    访问目录

    目前Scala没有正式的用来访问某个目录中的所有文件,或者递归的遍历所有目录。

    import java.io.File
    def subdirs(dir: File): Iterator[File] = {
        val children = dir.listFiles.filter(_.isDirectory)
        children.toIterator ++ children.toIterator.flatMap(subdirs _)
    }
    
    // 访问所有子目录
    for (d <- subdirs(dir)) 处理 d
    

    序列化

    在Java中,我们用序列化来将对象传输到其他虚拟机,或者临时存储。

    // Java
    public class Person implements java.io.Serializable {
        private static final long serialVersionUID = 42L;
        ...
    }
    
    // Scala
    @SerialVersionUID(42L) class Person extends Serializable
    
    val fred = new Person(...)
    import java.io._
    val out = new ObjectOutputStream(new FileOutputStream("/tmp/test.obj"))
    out.writeObject(fred)
    out.close()
    
    val in = new ObjectInputStream(new FileInputStream("/tmp/test.obj"))
    val savedFred = in.readObject().asInstanceOf[Person]
    

    Scala的集合类都是可序列化的,因此你可以把它们用做你的可序列化类成员:

    class Person extends Serializable {
        private val friends = new ArrayBuffer[Person]
        ...
    }
    

    正则表达式

    使用scala.util.matching.Regex类

    val numPattern = "[0-9]".r
    
    val wsnumwsPattern = """\s+[0-9]\s""".r  // 处理反斜杠或引号
    
    // findAllIn方法返回遍历所有匹配项的迭代器
    for (matchString <- numPattern.findAllIn("99 bottles, 98 bottles")) 处理matchString
    
    // 将迭代器转换为数组
    val matches = numPattern.findAllIn("99 bottles, 98 bottles")).toArray   // Array(99, 98)
    
    // 找到字符串的首个匹配项:
    val m1 = wsnumwsPattern .findFirstIn("99 bottles, 98 bottles")  // Some(" 98 ")
    
    // 检查是否某个字符串的开始部分能匹配
    numPattern.findPrefixOf("99 bottles, 98 bottles")     // Some(99)
    wsnumwsPattern .findPrefixOf("99 bottles, 98 bottles") // None
    
    // 替换
    numPattern.replaceFirstIn("99 bottles, 98 bottles", XX)  // "XX bottles, 98 bottles"
     numPattern.replaceAllIn("99 bottles, 98 bottles", XX)    // "XX bottles, XX bottles"
    

    正则表达式组

    分组可以让我们方便的获取正则表达式的子表达式。要提取的子表达式两侧加上圆括号,例如:

    val numitemPattern = "([0-9]+) ([a-z]+)".r
    // 要匹配组,可以把正则表达式对象当做"提取器"使用
    val numitemPattern(num, item) = "99 bottles"  // 将num设为"99", item设为"bottles"
    
    for (numitemPattern(num, item) <- numitemPattern.findAllIn("99 bottles, 98 bottls")) {
        处理num和item
    }
    

    相关文章

      网友评论

          本文标题:快学Scala第9章----文件和正则表达式

          本文链接:https://www.haomeiwen.com/subject/uqtgdttx.html