1. 程式人生 > >Scala入門到精通——第十二節 I/O與正則表示式

Scala入門到精通——第十二節 I/O與正則表示式

本節主要內容

  1. Scala I/O操作簡介
  2. Scala 寫檔案
  3. Scala 讀檔案
  4. Scala 網路I/O
  5. 正則表示式簡介
  6. Scala正則表示式實戰

1. Scala I/O操作簡介

I/O操作是一門程式語言中的重要內容,在Scala中,它更多的是呼叫java中的I/O類或者通過對java中的I/O類進行相應的封裝來實現I/O操作。在上一節內容中我們已經用到了I/O操作:

trait FileLogger extends Logger{

  val fileName:String
  //PrintWriter使用的是java.io.PrintWriter類
  val fileOutput=new
PrintWriter(fileName:String) fileOutput.println("#") def log(msg:String):Unit={ fileOutput.print(msg) fileOutput.flush() } }

scala自身關於I/O的內容比較少,下圖給出的是scala I/O相關的類
這裡寫圖片描述
可以看到,相比於java語言中的I/O類,scala語言中的I/O相關類數量就顯得少得多,而這其中最常用的只有Source這個類,因此要學好scala I/O操作,必須對java中的I/O相關類有個比較深入的瞭解。

2. Scala 寫檔案

Scala進行檔案寫操作,直接用的都是java中的I/O類,例如

import java.io._

object ScalaFileWriter {
  def main(args: Array[String]): Unit = {
    val fileWriter=new FileWriter("file.txt")
    fileWriter.write("scala file writer")
    fileWriter.flush()
    fileWriter.close()
  }
}

可以看出 scala中的檔案寫操作與java中的I/O操作並沒有什麼區別,這說明了scala可以與java進行互操作。

3. 讀檔案

scala中讀檔案可以直接使用java中的I/O類,也可以用scala中的Source物件,該物件對java中的I/O進行了封裝,使用更簡便更靈活,下面的程式碼給出瞭如果讀取檔案並將檔案內容格式化輸出:

import scala.io._

object ScalaFileReader {
  def main(args: Array[String]): Unit = {
    //讀取檔案
    val file=Source.fromFile("D:\\scala\\doc\\api\\package.html")
    //返回Iterator[String]
    val lines=file.getLines()
    //列印內容
    for(i<- lines) println(i)  
    //關閉檔案
    file.close();
  }
}

4. 網路I/O

scala中的網路I/O操作可以通過Source物件中的fromURL方法來實現,也可以使用原生的JAVA 網路I/O操作進行,下面的程式碼演示的是scala中的網路I/O讀取百度首頁內容:

import java.net.{URL, URLEncoder} 
import scala.io.Source.fromURL

object NetworkIO {
  def main(args: Array[String]): Unit = {
    print(fromURL(new URL("http://www.baidu.com")).mkString)
  }
}

5 正則表示式簡介

在眾多的程式語言當中,包括JAVA、Perl、PHP、Python、JavaScript和JScript,都無一例外內生地支援正則表示式處理。Scala語言同樣支援正則表示式,當然,scala可以直接通過Java操作正則表示式的方式使用正則表示式,但scala實現了自己的方式,它更為靈活。值得一提的是正則表示式並不只屬於某一門程式語言,它已經超出了某種語言或某個系統的侷限,成為被人們廣為使用的工具。
在程式開發中,經常會碰到需要匹配、查詢、替換、判斷字串,如果用純編碼方式解決的話,難度較大,而且很浪費時間,通過正則表示式可以解決這些問題。下面給出正則表示式中常用符號的含義:
1 句點符號.,它是一種萬用字元,用於匹配一個字元,例如Spa.k,可以匹配Spark、Spaak等任意字母組成的字串,還可以匹配Spa#k,Spa k等特殊字元組成的字串
2 [],限定匹配,例如Spa[ark]k只會匹配Spark,Spaak,Spakk這三個字串,對於其它的不會匹配
3 |, 或匹配,例如Spa(a|r|rr|k)k,則可以匹配Spark,Spaak,Spakk及Sparrk
4 $,匹配行結束符,例如Spark$ 匹配的是以Spark$ 為結尾行,例如I love Spark,但它不匹配Spark will be very poupular in the future
5 ^,匹配行開始符,例如^Spark匹配的是以Spark開始的行,如Spark will be very poupular in the future,不匹配I love Spark
6 *,匹配0至多個字元,例如Spar*,可以匹配任何Spar開始的字串,如Spar,Spark,Sparkkkkk
7 /,轉義符,例如Spark/$ 匹配的是包含Spark$的字串
8 ( ),分組符,它會將()中匹配的內容儲存起來,可以對其進行訪問,例如Spa(a|r|rr|k)k可以對()中匹配的內容儲存為一個臨時變數,在程式中可以直接對其進行訪問
9 +,匹配一次或多次例如Spar+,可以匹配任何Spar開始的字串,如Spark,Sparkkkkk
10 ?,匹配0次或一次,例如Spark(s)? 可以匹配Spark和Sparks
11 {n},匹配n次,例如Spark{2},可以匹配I love Sparkk中的Sparkk
12 {n,},至少匹配n次,例如Spark{2,}可以匹配I love Sparksss Sparkss中的Sparksss和Sparkss
13 {n,m},至少匹配n次,最多匹配m次,Sparks{2,4}可以匹配I love Sparks Sparkssss中的Sparkssss

限定匹配[]的用法非常靈活,有必要對其進行進一步的說明:

[a-z]     條件限制在小寫a to z範圍中一個字元
[A-Z]     條件限制在大寫A to Z範圍中一個字元
[a-zA-Z] 條件限制在小寫a to z或大寫A to Z範圍中一個字元
[0-9]     條件限制在小寫0 to 9範圍中一個字元
[0-9a-z] 條件限制在小寫0 to 9a to z範圍中一個字元
[0-9[a-z]] 條件限制在小寫0 to 9a to z範圍中一個字元(交集)
^符號在限定匹配[]中有另外的含義,即取反操作
[^a-z]     條件限制在非小寫a to z範圍中一個字元
[^A-Z]     條件限制在非大寫A to Z範圍中一個字元
[^a-zA-Z] 條件限制在非小寫a to z或大寫A to Z範圍中一個字元
[^0-9]     條件限制在非小寫0 to 9範圍中一個字元
[^0-9a-z] 條件限制在非小寫0 to 9a to z範圍中一個字元

其它特殊字元:
\ 反斜槓
\t 間隔 (‘/u0009’)
\n 換行 (‘/u000A’)
\r 回車 (‘/u000D’)
\d 數字 等價於[0-9]
\D 非數字 等價於[^0-9]
\s 空白符號 [/t/n/x0B/f/r]
\S 非空白符號 [^/t/n/x0B/f/r]
\w 單獨字元 [a-zA-Z_0-9]
\W 非單獨字元 [^a-zA-Z_0-9]
\f 換頁符
\e Escape
\b 一個單詞的邊界
\B 一個非單詞的邊界
\G 前一個匹配的結束

6 常用正則表示式實戰

下面給出最為常用的幾種正則表示式的操作來領略正則表示式的魅力及它在scala中是如何使用的。
1 匹配郵箱:

object RegexMatch {
  def main(args: Array[String]): Unit = {
    val sparkRegex="^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$".r
    for(matchString <- sparkRegex.findAllIn("[email protected]"))
    {
      println(matchString)
    }
  }
}

2 匹配網址:

object RegexMatch {
  def main(args: Array[String]): Unit = {
    val sparkRegex="^[a-zA-Z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\s*)?$".r
    for(matchString <- sparkRegex.findAllIn("http://www.xuetuwuyou.com"))
    {
      println(matchString)
    }
  }
}

3 匹配手機號碼:

object RegexMatch {
  def main(args: Array[String]): Unit = {
    val sparkRegex="(86)*0*13\\d{9}".r
    for(matchString <- sparkRegex.findAllIn("13887888888"))
    {
      println(matchString)
    }
  }
}

4 匹配IP地址:


object RegexMatch {
  def main(args: Array[String]): Unit = {
    val sparkRegex="(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)".r
    for(matchString <- sparkRegex.findAllIn("192.168.1.1"))
    {
      println(matchString)
    }
  }
}

在scala中,有一個非常非常強大的功能,那就是提取器(Extractor),在後面我們會專門拿一講來講解scala的提取器,本節只是簡單演示一下提取器是如何與scala中的正則表示式一直使用的。

提取匹配的IP地址子段:

object RegexMatch {
  def main(args: Array[String]): Unit = {
    val ipRegex="(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)".r
    for(ipRegex(one,two,three,four) <- ipRegex.findAllIn("192.168.1.1"))
    {
      println("IP子段1:"+one)
      println("IP子段2:"+two)
      println("IP子段3:"+three)
      println("IP子段4:"+four)
    }
  }
}

提取郵箱中的使用者名稱:

object RegexMatch {
  def main(args: Array[String]): Unit = {
    val sparkRegex="^([\\w-]+(\\.[\\w-]+)*)@[\\w-]+(\\.[\\w-]+)+$".r
    for(sparkRegex(domainName,_*) <- sparkRegex.findAllIn("[email protected]"))
    {
      println(domainName)
    }
  }
}

新增公眾微訊號,可以瞭解更多最新Spark、Scala相關技術資訊
這裡寫圖片描述