目录
一、什么是正则表达式?
正则表达式(简称:regex)是一个字符串,用来描述匹配一个字符串集合的模式。对于字符串处理来说,正则表达式是一个强大的工具。可以使用正则表达式来匹配、替换和拆分字符串。
二、正则表达式的使用之匹配字符串
String类中有一个查找字符串中是否包含某个字符的方法--matches方法,同时也有一个方法--equals与matches方法类似。
e.g
"Java".matches("Java");
"Java".equals("Java");
这两个语句返回值都为True。
然而matches的功能更加强大。以上两种都是匹配的一个固定的字符串"Java",matches还可以匹配符合一个模式的字符串集。
e.g
"Java is fun".matches("Java.*")
"Java is cool".matches("Java.*")
"Java is powerful".matches("Java.*")
以上语句返回值都为True。
语句中的"Java.*"是一个正则表达式。它描述了一个字符串模式,以Java开始,后面跟0个或多个字符串。这里,子字符串.*匹配0或多个任意字符串。
三、正则表达式语法
正则表达式由字面值字符和特殊符号组成。
下表是一些常用的正则表达式
tips:反斜杠‘ \ ’是特殊字符,Java中需要用‘ \\ ’来表示它。
tips:空白字符是 ‘ ’、‘ \t ' 、' \n '、' \r '、' \f '。因此 \s 和[\t \n \r \f]等同,\S和[^ \t \n \r \f]等同。
tips:单词字符是任何的字母,数字或者下划线字符。因此 \w 等同于[ a-z[A-Z][0-9]_]或者简化为 [a-Za-z0-9_]。\W等同于[^a-Za-z0-9]。
tips:表中后面六个条目 * 、+、?、{n}、{n, }以及{n,m}称为量词符,用于确定量词符前面的模式会重复多少次。
例如,A*匹配0或多个A,A+匹配1或者多个A,A?匹配0或者1个A。A{3}精准匹配“AAA”, A{3, }匹配至少3个A,A{3,6}匹配3到6个A。*等同于{0,},+等同于{1,},?等同于{0.1}。
警告:不要在重复量词符中使用空白。例如,A{3,6}不能写成逗号后面还有一个空白符的A{3, 6}。
tips:可以用括号来将模式进行分组。例如,(ab){3}匹配ababab,但是ab{3}匹配abbb.
下面是一些示例构建正则表达式。
1·示例 1
社会安全号的模式是xxx-xx-xxxx,其中x是一位数字。社会安全号的正则表达式可以描述为
[\\d]{3}-[\\d]{2}-[\\d]{4}
例如
"111-22-3333".matches("[\\d]{3}-[\\d]{2}-[\\d]{4}") return true.
"11-22-3333".matches("[\\d]{3}-[\\d]{2}-[\\d]{4}") return false.
2·示例 2
偶数以数字0、2、4、6、8结尾。偶数模式可以描述为
[\\d]*[02468]
例如,
"123".matches("[\\d]*[02468]") return false.
"122".matches("[\\d]*[02468]") return true.
注意:这里的[\\d]指的是“123”里面靠近matches最近的一个数字“3”,和“122”的“2”,而不是“123”和“122“这两个数。
3·示例 3
电话号码的模式是(xxx)xxx-xxxx,这里x是一位数字,并且第一位数字不能为0。电话号码的正则表达式可以描述为
\\([1-9][\\d]{2}\\)[\\d]{3}-[\\d]{4}
tips:括号符” ( “和” )“在正则表达式中是特殊字符,用于对模式分组。为了在正则表达式中表示字面值”( “和” )“时,必须用” \\( “和” \\) “。
例如
"(912) 921-2728".matches("\\([1-9][\\d]{2}\\)[\\d]{3}-[\\d]{4}")
return true.
"921-2728".matches("\\([1-9][\\d]{2}\\)[\\d]{3}-[\\d]{4}")
return false.
4·示例 4
假定姓最多由25个字母组成,并且第一个字母为大写形式。则姓的模式可以描述为
[A-Z][a-zA-Z]{1,24}
tips:不能随便放空白符到正则表达式中。如[A-Z][a-zA-Z]{1, 24}将报错
例如
"Smith".matches("[A-Z][a-zA-Z]{1,24}") return true.
"Jones123".matches("[A-Z][a-zA-Z]{1,24}") return false.
5.示例 5
Java标识符
⚪ 标识符必须以字母、下划线(_),或者美元符号($)开始。不能以数字开头。
⚪ 标识符是一个由字母、数字、下划线(_)和美元符号组成的字符序列。
标识符的模式可描述为
[a-zA-Z_$][\\w$]*
6·示例 6
什么字符串匹配正则表达式“Welcome to (Java|HTML)"?答案是Welcome to Java或者Welcome to HTML。
7·示例 7
什么字符串匹配正则表达式" .*"?答案是任何字符串。
四、替换和拆分字符串
如果字符串匹配正则表达式,String类的matches方法返回 true。String类也包含repalceAll、replaceFirst和split方法,用于替换和拆分字符串,如下图所示。
replaceALL方法替换所有匹配的子字符串,replaceFirst方法替换第一个匹配的字符串。例如
代码
System.out.println("Java Java Java".replaceAll("v\\w","wi"));
显示
Jawi Jawi Jawi
代码
System.out.println("Java Java Java".replaceFirst("v\\w","wi"));
显示
Jawi Java Java
有两个重载的 split 方法。split(regex)方法使用匹配的分隔符将一个字符串拆分为子字符串。
例如,以下语句
String[] tokens = "Java1HTML2Per1".split("\\d");
将字符串"JavaHTML2Per1"拆分为Java、HTML 以及Per1并且保存在tokens[0],tokens[1]以及tokens[2]中。
在split(regex,limit)方法中,limit参数确定模式匹配多少次。如果1imit <= 0,split(regex,1imit)等同于split(regex)。如果limit > 0,模式最多匹配1imit -1次。
下面是一些示例:
"Java1HTML2Perl".split("\\d",0);拆分为Java,HTML,Perl
"Java1HTML2Perl".split("\\d",1);拆分为Java1HTML2Perl
"Java1HTML2Perl".split("\\d",2);拆分为Java,HTML2Perl
"Java1HTML2Perl".split("\\d",3);拆分为Java,HTML,Perl
"Java1HTML2Perl".split("\\d",4);拆分为Java,HTML,Perl
"Java1HTML2Perl".split("\\d",5);拆分为Java,HTML,Perl
注意:默认情况下,所有的量词符都是“贪婪”的。这意味着它们会尽可能匹配最多次。比如,下面语句显示JRvaa。因为第一个匹配成功的是aaa。
System.out.println("Jaaavaa".replaceFirst("a+","R"));
可以通过在后面添加问号(?)来改变量词符的默认行为。量词符变为“不情愿”或者“惰性”的,这意味着它将匹配尽可能少的次数。例如,下面的语句显示]Raavaa,因为第一个匹配成功的是a。
System.out.println("Jaaavaa".replaceFirst("a+?”,"R"));