众所周知,在程序开发中,难免会遇到需要匹配、查找、替换、判断字符串的情况发生,而这些情况有时又比较复杂,如果用纯编码方式解决,往往会浪费程序员的时间及精力。因此,学习及使用正则表达式,便成了解决这一矛盾的主要手段。
正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
而Scala 的正则表达式继承了 Java 的语法规则,Java 则大部分使用了 Perl 语言的规则。
Scala 通过 scala.util.matching 包中的 Regex 类来支持正则表达式。
使用“.r” 方法可使任意字符串变成一个Regex实例
举些一般常用的正则表达式规则:
^
匹配输入字符串开始的位置。
$
匹配输入字符串结尾的位置
.
匹配任意一个字符
[ ]
匹配字符集,匹配括号包含的任一字符一次
[Rr]uby
匹配 "Ruby" 或 "ruby"
[…-…]
匹配括号内指定范围的字符集, - 表示区间内的任意一个字符或数字
[0-9]
匹配任何数字,类似 [0123456789]
[a-z]
匹配任何 ASCII 小写字母
[A-Z]
匹配任何 ASCII 大写字母
[a-zA-Z0-9]
匹配数字,大小写字母
[^]
匹配字符集,匹配括号内不包含的任一字符
[^abc]
匹配"plain"中"p","l","i","n"
[^abcde]
匹配除了 abcde 其他字符
\A
匹配输入字符串开始的位置
\z
字符串结尾(类似$,但不受处理多行选项的影响)
\Z
字符串结尾或行尾(类似$,但不受处理多行选项的影响)
*
表示匹配该符号前面的字符出现0次、1次或多次
abcde*
匹配 "abcd" 加上 0 个1个或多个的 e。
+
表示匹配该符号前面的字符出现1次或多次
abcde+
匹配 "abcde" 或加多个的 e。
?
表示匹配该符号前面的字符出现0次或1次
abcde?
匹配 "abcd" 或"abcde"。
{n}
匹配符号前面的字符出现次数由括号内的数字n定义
abcde{3}
匹配"abcdeee" 有3个e
{n,m}
匹配符号前面的字符出现n~m次
abcde{1,3}
匹配"abcd" 后面有1个e或2个e或有3个e
{n,}
匹配符号前面的字符出现n次或n次以上
abcde{3,}
匹配"abcd" 后面有3个e 或3个以上e
()
匹配括号内的所有字符是一个整体,并捕获文本到自动命名的组里
(abcde)
匹配"abcde"
(?: )
匹配 括号内字符,不捕获匹配的文本,也不给此分组分配组号
(?> )
贪婪子表达式
|
匹配符号左右两边任意一边
food|f
匹配的是foo(d或f)
\d
匹配数字,等同于 [0-9]
\D
匹配非数字,等同于 [^0-9]
\w
匹配字母或数字或下划线或汉字,等同于[0-9a-zA-Z_]
\W
匹配任意不是字母,数字,下划线,汉字的字符,等同于 [^0-9a-zA-Z_]
\s
匹配任意的空白符,等同于 [\t\n\r\f]
\S
匹配任意不是空白符的字符
\b
通常是单词分界位置,但如果在字符类里使用代表退格
\B
匹配不是单词开头或结束的位置
模式匹配,Regex实现了提取器
Scala中将字符串转换为正则表达式 使用 .r方法
// """原生表达
val regex="""([0-9]+) ([a-zA-Z]+)""".r
// 按空格匹配2组,第一组为任意数字,第二组为任意字母
"L3R 6M2" match {
//x为第1个分组结果,可以匹配多个分组
case regex(x) => println("Valid zip-code:"+ x)
case x => println("Invalid zip-code: " + x )
}
//结果
Invalid zip-code: L3R 6M2
matches匹配
String.matches()方法
"!123".matches("[a-zA-Z0-9]{4}") //false
"34Az".matches("[a-zA-Z0-9]{4}") //true
findFirstMatchIn() 返回第一个匹配项(Option[Match])
findFirstMatchIn() 返回的是Option[Match]对象,所以用Some和None
先导包 import scala.util.matching.Regex
val numberPattern: Regex = "[0-9]{3}".r
numberPattern.findFirstMatchIn("som3e5pa7ssword") match {
case Some(_) => println("Password OK") //匹配成功
case None => println("Password must contain a number") //未匹配
}
//结果
Password must contain a number //未匹配
findAllMatchIn() 返回所有匹配结果(Regex.Match)
匹配成功返回所有匹配结果是个集合
val number: Regex = "[a-z]{3}".r
number.findAllMatchIn("123qwefdfeacxrer").foreach(println)
//结果
qwe
fdf
eac
xre
findAllIn() 返回所有匹配结果(String)
匹配成功返回所有匹配结果是个字符串类型的迭代器,必须要先变成集合,再循环打印
val number: Regex = "[a-z]{3}".r
(number.findAllIn("123qwefdfeacxrer")).toList.foreach(println)
//结果
qwe
fdf
eac
xre
捕获分组
主要识别键值对,对键值对分组,键key为一组,值value为一组
val student1:Regex = "([0-9a-zA-Z-#() ]+):([0-9a-zA-Z-#() ]+)".r
val input1="name:Jason,age:19,weight:100"
student1.findAllMatchIn(input1).foreach(x=>println
(s"key:${x.group(1)},value:${x.group(2)}")) //s表示el表达式
//结果
key:name,value:Jason
key:age,value:19
key:weight,value:100
字符串替换
replaceFirstIn 替换第一个匹配项
object Test {
def main(args: Array[String]) {
val regex = "(S|s)cala".r
val str = "Scala is scalable and cool"
println(regex replaceFirstIn(str, "Java"))
}
}
//结果
Java is scalable and cool //大写的S先匹配,替换成java
replaceAllln 替换所有匹配项
"[0-9]+".r.replaceAllIn("234 Main Street Suite 2034", "567")
//结果
567 Main Street Suite 567
在字符串中模式匹配查找多组
正则解析多组,使用模式匹配一个组一个组对接匹配
// """原生表达
val date = """(\d{4})-(\d{1,2})-(\d{1,2})""".r //根据-分成3组
"2020-7-15" match{
case date(year,month,day)=>println(year,month,day)//匹配的时候接收3个组一 一对接
}
//结果
2020,7,15
//接收一组
"2020-7-15" match{
case date(year,_*)=>println(year)
}
//结果
2020
对数组进行模式匹配多组查找
//根据空格对每一行数据分三组
val str = Array("INEO 2016-07-25 requestURI:/c?app=0&p=1&did=2",
"WARNING 2016-06-26 requestURI:/c?app=0&p=2&did=1",
"ERROR 2016-08-27 requestURI:/c?app=0&p=1&did=1")
var regex = """([a-zA-Z]{4,8}) ([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}) (.*)""".r
str.foreach(x=>x match{
case regex(k,v,w)=>println(k,v,w) //获取所有的分组 k表示第一组,v表示第二组,w表示第三组
case regex(k,_*)=>println(k) //获取第一组
}
)
// 第一组的结果
INEO
WARNING
ERROR