目录
-
- [第十五章 文件和正则表达式](#第十五章 文件和正则表达式)
-
- [1- 读取行](#1- 读取行)
- [2- 从URL或者其它源读取](#2- 从URL或者其它源读取)
- [3- 写入文本文件](#3- 写入文本文件)
- [4- 序列化](#4- 序列化)
- [5- 正则表达式](#5- 正则表达式)
- [6- 正则表达式验证输入数据格式](#6- 正则表达式验证输入数据格式)
- end
第十五章 文件和正则表达式
1- 读取行
在Scala中读取文件中的行可以通过不同的方法实现 ;
一种常见的方法是使用 scala.io.Source
对象来逐行读取文件内容 ;
示例 :
scala
import scala.io.Source
object FileReadingLinesExample {
def main(args: Array[String]): Unit = {
val fileName = "src/main/resources/test.txt"
try {
val source = Source.fromFile(fileName)
val lines = source.getLines().toList
source.close()
println("文中的行: ")
lines.foreach(println)
} catch {
case e: Exception => println("文件读取错误: " + e.getMessage)
}
}
}
shell
# 输出
文中的行:
《登雀鹤楼》
唐.王之涣
白日依山尽,
黄河入海流。
欲穷千里目,
更上一层楼。
在这个示例中, 我首先导入了 scala.io.Source
类 ;
然后, 我们指定要读取的文件名, 并使用 Source.fromFile(fileName)
创建一个 Source
对象 ;
接着, 我们使用 getLines()
方法逐行读取文件内容, 并将每行存储在一个列表中 ;
最后, 我们关闭文件流并打印出读取的所有行 .
注意, 这只是一个简单的示例, 实际应用中可能需要更多的错误处理和资源管理 ;
确保文件存在并具有适当的读取权限 ;
你可以根据需要进一步扩展和优化这段代码 .
2- 从URL或者其它源读取
在Scala中, 你可以使用 scala.io.Source
类来从URL或其他来源读取文件内容 ;
示例 :
scala
import scala.io.Source
import java.net.URL
object URLReadingExample {
def main(args: Array[String]): Unit = {
val url = new URL("https://raw.githubusercontent.com/dpx0110/files/main/poem.txt")
try {
val source = Source.fromURL(url)
val content = source.mkString
source.close()
println("从URL读取的文件内容: ")
println(content)
} catch {
case e: Exception => println(s"Error reading URL: ${e.getMessage}")
}
}
}
- 在这个示例中, 我们导入了
scala.io.Source
类和java.net.URL
类 ; - 然后, 我们创建一个
URL
对象, 指定要读取的URL地址 ; - 接着, 我们使用
Source.fromURL(url)
方法从URL读取文件内容, 并将其存储为字符串 ; - 最后, 我们关闭文件流并打印出读取的内容 .
scala
// 其它源读取
val source1 = Source.fromString("hello world! ")
val source2 = Source.stdin
...
请确保URL地址有效并具有适当的访问权限 ;
根据实际情况修改URL地址, 以适应你的文件读取需求 ;
这段代码可以帮助你从URL或其他来源读取文件内容 .
3- 写入文本文件
在Scala中写入文本文件, 可以使用多种方法, 一下是几种常见方式 :
**1. 使用 java.io.PrintWriter
**
这是最直接的方式, 利用 Java 的 PrintWriter
类写入数据到文件 ;
scala
import java.io.PrintWriter
object WriteToFile {
def main(args: Array[String]): Unit = {
val filePath = "src/main/resources/poem1.txt"
val writer = new PrintWriter(filePath)
try {
writer.println("《题西林壁》")
writer.println("宋.苏轼")
writer.println("横看成岭侧成峰,")
writer.println("远近高低各不同。")
writer.println("不识庐山真面目,")
writer.println("只缘身在此山中。")
} finally {
writer.close()
}
}
}
shell
《题西林壁》
宋.苏轼
横看成岭侧成峰,
远近高低各不同。
不识庐山真面目,
只缘身在此山中。
2. 使用 java.io.FileWriter
和 java.io.BufferedWriter
这种方式更注重效率, BufferedWriter
可以提高写入效率, 尤其在处理大量数据时 ;
scala
import java.io.{BufferedWriter, FileWriter}
object WriteToFile {
def main(args: Array[String]): Unit = {
val filePath = "src/main/resources/poem2.txt"
val writer = new FileWriter(filePath)
val bufferedWriter = new BufferedWriter(writer)
try {
bufferedWriter.write("《题西林壁》\n") // 须手动添加换行符
bufferedWriter.write("宋.苏轼\n")
bufferedWriter.write("横看成岭侧成峰,\n")
bufferedWriter.write("远近高低各不同。\n")
bufferedWriter.write("不识庐山真面目,\n")
bufferedWriter.write("只缘身在此山中。\n")
} finally {
bufferedWriter.close()
}
}
}
shell
《题西林壁》
宋.苏轼
横看成岭侧成峰,
远近高低各不同。
不识庐山真面目,
只缘身在此山中。
4- 序列化
在分布式系统、大数据处理以及需要将对象状态保存到磁盘的场景中, 序列化扮演着至关重要的角色 ;
Scala作为一门运行于Java虚拟机上的语言, 自然也需要处理对象的序列化和反序列化问题 ;
Scala本身没有提供原生的序列化机制, 而是依赖于Java的序列化机制或第三方库来实现 ;
1. 使用Java序列化
最直接的方式是使用Java自带的序列化机制 ;
你只需要让你的类继承 java.io.Serializzble
接口 , 并添加 serialVersionUID
即可 ;
scala
// 序列化 和 反序列化
import java.io._
@SerialVersionUID(100L)
class Person(val name: String, val age: Int) extends Serializable {
override def toString: String = s"Person(name=$name, age=$age)"
}
// 序列化
val person = new Person("Tom", 18)
val outputStream = new FileOutputStream("person.ser")
val objectOutputStream = new ObjectOutputStream(outputStream)
objectOutputStream.writeObject(person)
objectOutputStream.close()
// 反序列化
val inputStream = new FileInputStream("person.ser")
val objectInputStream = new ObjectInputStream(inputStream)
val loadedPerson = objectInputStream.readObject().asInstanceOf[Person]
objectInputStream.close()
println(loadedPerson) // Output: Person(name=Tom, age=18)
println(loadedPerson.getClass) // Output: class org.puture.scala.MyFiles$Person$1
println(loadedPerson.name) // Output: Tom
println(loadedPerson.age) // Output: 18
- 优点: 简单直接, 开箱即用
- 缺点:
- 只能序列化实现了
java.io.Serializable
接口的类 - 序列化后的数据格式与Java绑定, 不够灵活
- 性能相对较低
- 只能序列化实现了
2. 使用第三方库
为了克服Java序列化的缺点, Scala社区涌现出许多优秀的第三方序列化库, 例如:
- Json库:
- uPickle: 专注于速度和简洁性, 使用宏生成高效的序列化代码 ;
- Circe: 类型安全, 功能强大, 支持多种数据格式 ;
- Play Json: Play框架的一部分, 易于使用, 适用于Web应用程序 ;
- 其他库:
- Kryo: 高性能序列化库, 适用于需要极致速度的场景 ;
- Chill: Twitter开发的序列化库, 支持多种数据格式, 包括Kryo和Json .
选择合适的序列化方式
选择哪种序列化方式取决于你的具体要求 :
- 简单项目: 如果你的项目比较简单, 对性能要求不高, 可以使用Java序列化或者uPickle ;
- **Web应用程序: ** 可以考虑使用Play Json, 它与Play框架集成良好 ;
- **高性能需求: ** 如果你的项目对性能要求很高, 可以考虑使用Kryo或者Chill ;
- **类型安全: ** 如果需要类型安全的序列化, 建议使用 Circe等库 ;
总而言之, Scala提供了多种方式类处理对象的序列化和反序列化, 你需要根据项目的具体情况选择合适的方式 .
5- 正则表达式
Scala中的正则表达式使用与 Java相同的语法, 但它提供了更简洁、更强大的方式来匹配和操作文本 ;
1. 基本语法
Scala中的正则表达式使用 r
字符串字面量来定义 ; 例如 :
scala
val regex = "hello".r
这个正则表达式将匹配字符串 "hello" ;
2. 常用元字符
.
: 匹配任意单个字符 ;*
: 匹配前面的字符零次或多次 ;+
: 匹配前面的字符一次或多次 ;?
: 匹配前面的字符零次或一次 ;|
: 匹配左边或右边的表达式 ;[]
: 匹配方括号内的任意字符 ;[^...]
: 匹配不在方括号内的任意字符 ;\d
: 匹配数字 ;\s
: 匹配空白字符 ;\w
: 匹配字母、数字或才划线 ;\b
: 匹配单词边界 ;^
: 匹配字符串开头 ;$
: 匹配字符串结尾 ;
3. 匹配文本
可以使用 findAllIn
方法来查找匹配的文本 ;
scala
val text = "Hello, world!"
val regex = "Hello".r
val matches = regex.findAllIn(text)
matches.foreach(println) // 输出: Hello
4. 替换文本
可以使用 replaceAllIn
方法来替换匹配的文本 ;
scala
val text = "Hello, world!"
val regex = "world".r
val replaced = regex.replaceAllIn(text, "Scala")
println(replaced) // Output: Hello, Scala!
5. 分组
可以使用 ()
来分组正则表达式, 并通过 group
方法获取匹配的子字符串 ;
scala
val text = "The quick brown fox jumps over the lazy dog."
val regex = "(.+) (.+) (.+)".r
val matches = regex.findAllMatchIn(text)
matches.foreach(m => {
println("Group 1: " + m.group(1)) // Group 1: The quick brown fox jumps over the
println("Group 2: " + m.group(2)) // Group 2: lazy
println("Group 3: " + m.group(3)) // Group 3: dog.
})
6. 捕获组
可以使用 find
方法来查找第一个匹配的文本, 并使用 group
方法获取捕获组的内容 ;
scala
val text = "The quick brown fox jumps over the lazy dog."
val regex = "(\\w+) (\\w+)".r
val matches = regex.findPrefixOf(text)
println(matches) // Output: Some(The quick)
if (matches.isDefined) {
val m = matches.get
println(m) // Output: The quick
}
7. 注意事项
- 正则表达式语法较为复杂, 需要仔细理解才能灵活运用 ;
- 正则表达式匹配效率可能较低, 特别是复杂的表达式, 需要谨慎使用 ;
- Scala 中的正则表达式支持Java的正则表达式语法, 可以参考Java文档了解更多细节 ;
总结
Scala中的正则表达式功能强大, 能够满足各种文本匹配和处理的需求 ;
希望以上介绍能够帮助你更好的理解Scala中的正则表达式 .
6- 正则表达式验证输入数据格式
在Scala中, 你可以使用正则表达式来验证输入数据的格式, 例如邮箱地址、手机号等 ;
1. 准备工作
首先, 需要定义一个正则表达式, 用来匹配目标格式的数据 ;
例如:
- 邮箱地址:
^.+@.+\\..+$
- 手机号:
^1[3-9]\\d{9}$
2. 代码示例
scala
object DataValidation {
def main(args: Array[String]): Unit = {
val emailRegex = "^.+@.+\\..+$".r
val phoneRegex = "^1[3-9]\\d{9}$".r
// 键盘输入
println("请输入邮箱地址:")
val email = scala.io.StdIn.readLine()
println("请输入手机号:")
val phone = scala.io.StdIn.readLine()
// 验证邮箱地址
if (emailRegex.findFirstIn(email).isDefined) {
println("邮箱地址格式正确")
} else {
println("邮箱地址格式错误")
}
// 验证手机号
if (phoneRegex.findFirstIn(phone).isDefined) {
println("手机号格式正确")
} else {
println("手机号格式错误")
}
}
}
shell
请输入邮箱地址:
6666@gmail.com
请输入手机号:
16688889999
邮箱地址格式正确
手机号格式正确
Process finished with exit code 0
请输入邮箱地址:
123.34@gamil.com
请输入手机号:
166888899996
邮箱地址格式正确
手机号格式错误
Process finished with exit code 0
3. 解释
Regex
类是Scala用于表示正则表达式的类 ;findFirstIn
方法用于查找字符串中第一个匹配正则表达式的字符串, 如果找到则返回Some(匹配的自字符串)
, 否则返回None
;isDefined
方法用于判断Option
类型的值是否为空 ;
4. 其它验证方法
除了使用 findFirstIn
方法, 还可以使用以下方法来验证数据格式 :
matches
方法: 判断整个字符串是否匹配正则表达式 ;replaceAllIn
方法: 将字符串中所有匹配正则表达式的部分替换成其他字符串 ;
5. 注意事项
- 正则表达式语法比较复杂, 需要仔细学习和理解 ;
- 使用正则表达式进行数据格式验证只能保证数据符合预期的格式, 无法保证数据的有效性 ;
- 例如: 验证有序地址格式, 并不能保证这个邮箱地址真实存在 ;
6. 扩展
除了验证邮箱地址和手机号, 还可以使用正则表达式来验证其他格式的数据, 例如:
- 日期格式
- 身份证号码
- 邮政编码
- URL地址
- ...