快學Scala-第九章 文件和正則表達式


知識點:

1.讀取文件中的所有行,可以調用scala.io.Source對象的getLines方法:

import scala.io.Source
val source = Source.from("myfile.txt","UTF-8")
//第一個參數可以使字符串或者是java.io.File
//如果已知文件使用的是當前平台缺省的字符編碼,則可以略去第二個字符編碼參數
val lineIteractor = source.getLines
//結果是一個迭代器
for(l <- lineIteractor) ...
//對迭代器應用toArray或者toBuffer方法,將行放到數組或數組緩沖
val lines = source.getLines.toArray
//讀取文件成一個字符串
val contents = source.mkString

使用完source對象后,需要調用close關閉。

2.讀取字符

要從文件中讀取單個字符,可以直接把Source對象當做迭代器,因為Source類擴展自Iterator[Char]: for (c <- source) 處理 c

如果你想看某個字符但又不處理的話,調用source對象的buffered方法。可以用head方法查看下一個字符,但同時不把它當做是已處理的字符。

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

3.讀取詞法單元和數字

讀取源文件中所有以空格隔開的詞法單元: val tokens = source.mkString.split(“\\s+”)

字符串轉換為數字,如果有浮點數文件,並讀取到數組

val numbers = for (w <- tokens) yield w.toDouble

或者

val numbers = tokens.map(_.toDouble)

也可以從控制台讀取數字,readInt() readDouble() readLong(), 這些方法假定下一行輸入包含單個數字,

4.從URL或其他源讀取

  val source1 = Source.fromURL("http://horstamnn.com","UTF-8")
  val source2 = Source.fromString("Hello,world!")//從給定的字符串讀取 對調試很有用
  val source3 = Source.stdin //從標准輸入讀取

5.讀取二進制文件 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()

6.寫入文本文件

Scala沒有內建的對寫入文件的支持,要寫入文件,可使用java.io.PrintWriter.

val out = new PrintWriter("numbers.txt")
  for(i <- 1 to 100) out.println(i)
  out.close()
  //當傳遞數字給printf方法時,編譯器會抱怨說你需要將它轉換成AnyRef:
  out.printf("%6d %10.2f",quantity.asInstanceOf[AnfRef],price.asInstanceOf[AnyRef])
  //為了避免這個麻煩,也可以用String類的format方法
  out.print("%6d %10.2f".format(quantity,price))

7.訪問目錄 目前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

8.序列化 在java中,使用序列化來將對象傳輸到其他虛擬機,或臨時存儲,對於長期存儲而言,序列化可能會比較笨拙。以下是如何在java和scala中聲明一個可被序列化的類。

//java
  public class Person implements java.io.Serializable{
    private static final long serialVersionUID = 42L;
    ...
  }
  //scala
  @SerialVersionUID(42L) class Person extends Serializable
  //serializable特質定義在scala包,不需要顯式引入,也可略去@SerialVersionUID注解

按照常規的方式進行對象的序列化和反序列化

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集合都是可序列化的,可以把它們用作可序列化類的成員。

9.正則表達式

scala.util.matching.Regex.構造一個Regex對象,用String類的r方法:

val numPattern = “[0-9]+”.r

如果正則表達式包含反斜杠或引號的話,最好使用“原始”字符串語法”””…”””,例如:

val wsnumwsPattern = “””\s+[0-9]+\s+”””.r

findAllIn方法返回遍歷所有匹配項的迭代器。可以在for循環中使用它:

for( matching <- numPattern.findAllIn(“99 bottles,98 bottles”))

  處理 matchString

或者將迭代器轉成數組:

val matches = numPattern.findAllIn(“99 bottles,98 bottles”))

//Array(99,98)

要找到字符串中的首個匹配項,可使用findFirstIn,得到Option[String].

val m1 = wsnumwsPattern.findFirstIn(“99 bottles,98 bottles”))

//Some(“98”)

檢查是否某個字符串的開始部分能匹配,可用findPrefixOf,可以替換首個匹配項或全部替換,使用replaceFirstIn,replaceAllIn.

10.正則表達式組

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 bottles”))

    處理  num  和  item

 

練習:參考網址

1.編寫一小段Scala代碼,將某個文件中的行倒轉順序(將最后一行作為第一行,依此類推)

import scala.io.Source
import java.io.PrintWriter
object chapterNine{
val path = "test.txt"
val source = Source.fromFile(path).getLines()
val sourceRev = source.toArray.reverse
val pw = new PrintWriter(path)
sourceRev.foreach(line => pw.write(line+"\n"))
pw.close()
}

2.編寫Scala程序,從一個帶有制表符的文件讀取內容,將每個制表符替換成一組空格,使得制表符隔開的n列仍然保持縱向對齊,並將結果寫入同一個文件

import scala.io.Source
import java.io.PrintWriter
object chapterNine {
  val path = "test.txt"
  val source = Source.fromFile(path).getLines()
  val result = for (t <- source) yield t.replaceAll("\\t", "    ")
  val pw = new PrintWriter(path)
  result.foreach(line => pw.write(line + "\n"))
  pw.close()
}

3.編寫一小段Scala代碼,從一個文件讀取內容並把所有字符數大於12的單詞打印到控制台。如果你能用單行代碼完成會有額外獎勵

import scala.io.Source

object chapterNine {
Source.fromFile("test.txt").mkString.split("\\s+").foreach(arg => if(arg.length > 12) println(arg))
}

4.編寫Scala程序,從包含浮點數的文本文件讀取內容,打印出文件中所有浮點數之和,平均值,最大值和最小值

import scala.io.Source

object chapterNine {
  val nums = Source.fromFile("test.txt").mkString.split("\\s+")
  var total = 0d
  nums.foreach(total += _.toDouble)
  println(total)
  println(total/nums.length)
  println(nums.max)
  println(nums.min)
}

5.編寫Scala程序,向文件中寫入2的n次方及其倒數,指數n從0到20。對齊各列

1       1

2       0.5

4       0.25

…       …

import java.io.PrintWriter

object chapterNine {
  val pw = new PrintWriter("test.txt")
  for(n <- 0 to 20){
    val t = BigDecimal(2).pow(n)
    pw.write(t.toString())
    pw.write("\t\t")
    pw.write((1/t).toString())
    pw.write("\n")
  }
}

6.編寫正則表達式,匹配Java或C++程序代碼中類似"like this,maybe with \" or\\"這樣的帶引號的字符串。編寫Scala程序將某個源文件中所有類似的字符串打印出來

import scala.io.Source

object chapterNine {
  val source = Source.fromFile("test.txt").mkString
  val pattern = "\\w+\\s+\"".r
  pattern.findAllIn(source).foreach(println)
}

7.編寫Scala程序,從文本文件讀取內容,並打印出所有的非浮點數的詞法單位。要求使用正則表達式

import scala.io.Source

object chapterNine {
  val source = Source.fromFile("test.txt").mkString
  val pattern = """[^((\d+\.){0,1}\d+)^\s+]+""".r
  pattern.findAllIn(source).foreach(println)
}

8.編寫Scala程序打印出某個網頁中所有img標簽的src屬性。使用正則表達式和分組

import scala.io.Source

object chapterNine {
  val source = Source.fromFile("test.txt").mkString
  val pattern = """<img[^>]+(src\s*=\s*"[^>^"]+")[^>]*>""".r
  for (pattern(str) <- pattern.findAllIn(source)) println(str)
}

9.編寫Scala程序,盤點給定目錄及其子目錄中總共有多少以.class為擴展名的文件

import java.io.File

object chapterNine {
  val path = "."

  val dir = new File(path)

  def subdirs(dir: File): Iterator[File] = {
    val children = dir.listFiles().filter(_.getName.endsWith("class"))
    children.toIterator ++ dir.listFiles().filter(_.isDirectory).toIterator.flatMap(subdirs _)
  }

  val n = subdirs(dir).length

  println(n)
}

10.擴展那個可序列化的Person類,讓它能以一個集合保存某個人的朋友信息。構造出一些Person對象,讓他們中的一些人成為朋友,然后將Array[Person]保存到文件。將這個數組從文件中重新讀出來,校驗朋友關系是否完好.

import collection.mutable.ArrayBuffer
import java.io.{ObjectInputStream, FileOutputStream, FileInputStream, ObjectOutputStream}

//注意,請在main中執行。腳本執行無法序列化。
class Person(var name:String) extends Serializable{
  val friends = new ArrayBuffer[Person]()

  def addFriend(friend : Person){
    friends += friend
  }

  override def toString() = {
    var str = "My name is " + name + " and my friends name is "
    friends.foreach(str += _.name + ",")
    str
  }
}

object chapterNine extends App{
  val p1 = new Person("Ivan")
  val p2 = new Person("F2")
  val p3 = new Person("F3")

  p1.addFriend(p2)
  p1.addFriend(p3)
  println(p1)

  val out = new ObjectOutputStream(new FileOutputStream("test.txt"))
  out.writeObject(p1)
  out.close()

  val in =  new ObjectInputStream(new FileInputStream("test.txt"))
  val p = in.readObject().asInstanceOf[Person]
  println(p)
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM