你好,游客 登录
背景:
阅读新闻

Scala正则表达式示例

[日期:2021-09-27] 来源:  作者: [字体: ]

本文来自艾叔编著的《零基础快速入门Scala》免费电子书,添加文末艾叔微信,获取完整版的PDF电子书

8.2  正则表达式示例

正则表达式是一个特殊的字符串,它使用计算机和人都能懂的方式,描述了一组字符的特征。我们可以使用正则表达式,方便地进行字符串分割、提取等操作。

下面列举正则表达式在字符串处理中的常见应用场景,我们可以通过学习这些例子,掌握正则表达式的基本使用。

8.2.1  分割单词

  1. 示例

本示例利用正则表达式,以空格、回车、换行、tab等空白字符作为分隔符,对文本文件/etc/hosts进行单词分割,代码如下。

1~5行,读取“/etc/hosts”,并将文件内容转换成一个字符串(String),并打印;

6行,对字符串进行分割,使用str.split方法,split传入的是“\\s+”这是一个正则表达式,\\s表示表示空格、回车、换行、tab等空白字符,后面的+号,表示空白字符数>=1个,返回的结果赋值给wordList,它是Array[String]类型;

      1 import scala.io.Source

      2 val src = Source.fromFile("/etc/hosts")

      3 val str = src.mkString

      4 println(str)

      5 src.close()

      6 val wordList = str.split("\\s+")

      7 for (s <- wordList) {

      8   println(s)

      9 }

注意

  • \\s表示空白字符,大写的\\S表示所有非空字符;
  • \\s++号表示一个或多个空白字符,每个字符只要是空白字符即可,不需要都相同。
  1. 转义字符

字符串中有些特殊字符,如双引号“”,它表示字符串的起始和结束位置,如果要在字符串中间插入一个双引号,该怎么办?如果直接插入,会认为字符串到此结束,为此,字符串使用引入了转义符,使用反斜杠\做转义符,例如\就表示双引号本身,直接插入到字符串中间,而不会被认为是字符串的起始或结束位置了。

\在字符串中也是一个特殊字符,如果要表示\本身,只需在前面加转义,即\\。声明一个带反斜杠的字符串变量“he\llo wor\\ld”,要写成下面的格式

val s = "he\\llo  wor\\\\ld"

接上面的例子,如果要使用反斜杠来分割s,则可以写成

val r = s.split("\\\\")

得到的结果是

Array(he, llo  wor, "", ld)

为了避免出现上面的空字符,可以写成

 val r = s.split("\\\\+")

得到的结果是

Array(he, llo  wor, ld)

解释,为什么反斜杠\在正则表达式中要用“\\\\”来表示呢?

首先,反斜杠在字符串中是特殊字符,需要转义,因此,字符串中反斜杠\\\来表示;

其次,反斜杠在正则表达式中又是特殊字符,就像+号在字符串中是普通字符,但在正则表达式中是特殊字符一样,在正则表达式中,如果要表示正常的+号,前面要加\进行转义,同样的道理,要在正则表达式中,表示反斜杠,也要转义,即\\,而在字符串中,\又需要转义,所以\\=>\\\\,就变成四个反斜杠了。

8.2.2  解析数字

本例解析出/etc/hosts”文件中所有数字,使用*作为分隔,输出所有数字组成的字符串,代码如下。

8.2.2.1  方法一:使用isDigit判断数字

1~5行,读取“/etc/hosts”,将文件内容转换成Stringstr指向该String

6行,调用str.splitstr进行分割,正则表达式是“[\\s:.]+”,其中中括号[]表示括号里面的内容可以有,也可以没有;+表示有至少一个[]\\s:.表示2个特征,特征间用冒号:隔开,第一个特殊是\\s,表示空白字符,第二个特殊是点.,表示普通的.,两个特征间没有顺序关系。因此,这个正则表达式表示的是:使用空白字符或.构成的组合,其中空白字符和.的个数、顺序都没有限制,但不管怎样,至少有1个空白字符或者1个点。在[]内使用冒号:还可以连接更多的特征。

7~12行,遍历分割后的String数组wordList,调用isNumber方法,判断分割出来的字符串是否是数字,如果是,将其转换成Int,存储到numList中;

13行,将numList中的元素使用*做分隔,组成一个字符串,输出。

      1 import scala.io.Source

      2 val src = Source.fromFile("/etc/hosts")

      3 val str = src.mkString

      4 println(str)

      5 src.close()

      6 val wordList = str.split("[\\s:.]+")

      7 import scala.collection.mutable.ArrayBuffer

      8 val numList = new ArrayBuffer[Int]

      9 for (s <- wordList) {

     10   if(isNumber(s))

     11     numList += s.toInt

     12 }

     13 println(numList.mkString("*"))

注意:中括号是括号的作用,是把括号里的数据当成一个整体(相当于四则运算中的小括号),它不是表示可有可无。

isNumber方法代码如下

2~5行,遍历字符串str,使用isDigit判断每个Char是否为数字,只要1个不是,就返回false

      1 def isNumber(str: String):Boolean ={

      2   for(c <- str){

      3     if(!c.isDigit){

      4       return false

      5     }

      6   }

      7   true

      8 }

结果如下

127*0*0*1*1

8.2.2.2  方法二:使用正则表达式直接提取数字

方法一首先要实现数字分割,要将数字分割出来,则要找到分隔符的特征,但往往这个特征不好找,方法一中描述的分隔符是空白符和.,但还是有一些数字无法分割,例如:localhost4中的4,它左侧的分隔符既不是.,也不是空白符,所以就分割不出来,会漏掉。

方法二,不做分割,直接利用正则表达式来解析数字,可以解决上面的问题,例子代码如下。

1~5行,读取“/etc/hosts”文件,将其转换成字符串,使用str指向该字符串;

7行,创建一个Regex正则表达式对象,描述的是数字特征,[0-9]表示09中的任意数字,[]+表示至少有1个数字,后面的.r返回Regex对象引用,赋值给pattern

8行,调用patternfindAllIn方法,传入待处理的字符串str,利用pattern中的正则表达式来得到所有的数字,存储为一个数组,赋值给wordList

9行,将wordList中所有数字拼接起来,中间使用*进行分隔,并打印输出。

      1 import scala.io.Source

      2 val src = Source.fromFile("/etc/hosts")

      3 val str = src.mkString

      4 println(str)

      5 src.close()

      6

      7 val pattern = "[0-9]+".r

      8 val wordList = pattern.findAllIn(str).toArray

      9 println(wordList.mkString("*"))

结果如下

127*0*0*1*4*4*4*1*6*6*6

和方法一对比,方法二可以找出所有的数字,不会漏掉结果,而且关键代码只有2行,更简洁。

 

8.2.3  解析汉字

本例实现了对网页文件中汉字的解析,分为3个步骤:1. 获取网页,转换成字符串;2. 使用正则表达式对字符串进行解析,提取出汉字,存储到数组;3. 打印输出数组。代码如下,请在REPL下执行。

使用Source.fromURL在线获取baidu网页,将其转换成字符串,使用str指向该字符串。

1 import scala.io.Source

2 val baidu = Source.fromURL("http://www.baidu.com")

3 val str = baidu.mkString

1行,编写汉字的正则表达式hzPattern\u4e00-\u9fa5unicode汉字范围,[\u4e00-\u9fa5]+表示1个或者多个汉字;

2行,使用findAllIn,提取str中所有符合hzPattern特征的字符串,使用rs迭代器去访问提取后的结果;

3行,使用foreach打印所提取的汉字。

1 val hzPattern = "[\u4e00-\u9fa5]+".r

2 val rs = hzPattern.findAllIn(str)

3 rs.foreach(println)

8.2.4  解析IP

本例实现了对文本文件中IP的解析,例子代码如下。

1~3行,读取/etc/hosts文件,将其转换为String,并使str指向它;

4行,编写IP地址的正则表达式pat[\\d]+表示非空数字组合,至少包含1个数字,IP地址就是由40~255的数字通过.连接组合而成的;

5行,使用patstr进行解析,提取符合条件的字符串,并提供迭代器ipList供访问;

6行,使用ipList输出解析出来的IP地址。

1 import scala.io.Source

2 val file = Source.fromFile("/etc/hosts")

3 val str = file.mkString

4 val pat = "[\\d]+.[\\d]+.[\\d]+.[\\d]+".r

5 val ipList = pat.findAllIn(str)

6 ipList.foreach(println)

8.2.5  解析网页中的href链接

本例实现了对网页文件中href链接的解析,可以获取所有href开头的链接,代码如下。

1~3行,获取www.sohu.com的主页信息,并将其转换成字符串,使用str指向该字符串;

4行,编写href链接的正则表达式urlPatternhref链接的特征是,以href开头,后面跟=,后面则是双引号扩住的内容。写成正则表达式是:"href=\"[^\\s]+\"",中就的\"是转义,表示普通的双引号,\\s表示空白字符,^\\s非空白字符,[^\\s]+表示至少有1个以上的非空白字符,^\\s也可以写成\\S

5行,按照正则表达式对str解析,提出所有符合条件的字符串,并提供迭代器urlList

6行,遍历urlList,打印每个href链接。

1  import scala.io.Source

2  val sohu = Source.fromURL("http://www.sohu.com")

3  val str = sohu.mkString

4  val urlPattern = "href=\"[^\\s]+\"".r

5  val urlList = urlPattern.findAllIn(str)

6  urlList.foreach(println)

 

加艾叔微信,加入Linux(Shell+Zabbix)、大数据(Spark+Hadoop)、云原生(Docker+Kubernetes)技术交流群

 

 

 

 

关注艾叔公众号,获取更多一手信息

 

 

 

收藏 推荐 打印 | 阅读:
相关新闻