本文章原来是在 2019.8.15 在《印象笔记》平台记录,现在 2020.3.18 搬运到博客来,并对部分内容进行补充说明。
1.正则表达式基本理论
(1)定义:符合一定规则的表达式
作用:用于专门操作字符串
(2)字符:
普通字符:字母,数字,下划线,没有特殊意义的标点符号(匹配与之相同的一个字符)
转义字符:\n 换行符,\t 制表符, \\ 代表\本身 , \$,\?,\},\+,\] 代表符号本身
(3)标准字符集合:
能够与多种字符匹配的表达式
***注意区分大小写,大写是取反的意思
\d 0~9的任意一个数字
\D 非数字
\w 任意一个字母或数字或下划线,即 A~Z,a~z,0~9,_ 中的一个
\W 匹配非字母,数字,下划线
\s 包括空格,制表符,换行符等空白字符的其中任意一个
\S 匹配非空白符
. 小数点可以匹配任意一个字符(除了换行符\n),
(如果匹配包含“\n”在内的所有字符,一般用[\s\S])
(4)自定义字符集合
[]方括号匹配方式,能够匹配方括号中的任意一个字符
[ab5@] 匹配“a”或“b”或“5”或“@”
[^abc] 匹配"a""b""c"之外的任意一个字符,^ 代表取反
[a-z] 匹配"a"到"z"之间的任意一个字母, - 代表从..到..
[^A-F0-3] 匹配"A"到"F","0"到"3"之外的字符
注意:
-除了^和-之外的特殊字符,如果包含在[]中,则失去其特殊意义
-
(5)量词
修饰匹配次数的符号
{n} 表达式重复n次
{m,n} 表达式至少重复m次,最多重复n次
{m,} 表达式至少重复m次
? 匹配表达式0次或者1次,相当于{0,1}
+ 表达式至少出现一次,相当于{1,}
* 表达式不出现或出现任意次,相当于{0,}
匹配模式:贪婪模式(默认)(匹配的字符越多越好)
非贪婪模式({}后面加"?")(匹配的字符越少越好)
(6)字符边界
匹配某种条件的位置(零宽度),而不是字符
^ 与字符串开始的地方匹配,写在左侧
$ 与字符串结束的地方匹配,写在右侧
\b 匹配一个单词边界,匹配位置:前面的字符和后面的字符不全是\w
(7)匹配模式
IGNRECASE 忽略大小写(默认区分大小写)
SINGLELINE 单行模式(只有一个开头和结尾,"."可以匹配包含换行符在内的任意字符)
MULTILINE 多行模式(每行都有开头和结尾,此模式下可用"\A"和"\Z"匹配整个文本的开始和结束位置)
(8)捕获组()
( " | " 分支结构,或,匹配左边或者右边 )
1.捕获组()
(1)整体用于修饰
(2)取匹配结果的时候,单独得到括号中的表达式
(3)每一对括号()会分配一个编号,使用()的捕获会根据左括号的顺序从1开始自动编号
2.非捕获组(?:Expression)
一些表达式中不得不使用(),但又不需要保存()中子表达式匹配的内容,
这时可以用非捕获组来抵消使用()带来的副作用
3.反向引用(\nnn)
通过反向引用,可以分组已捕获的字符串进行引用
(9)预搜索(零宽断言,环视)
-断言不计入匹配结果
(?=exp) 断言自身出现的位置后面能匹配表达式exp
(?<=exp) 断言自身出现的位置前面能匹配表达式exp
(?!exp) 断言自身出现的位置后面不能匹配表达式exp
(?<!exp) 断言自身出现的位置前面不能匹配表达式exp
2.正则表达式简单练习
(1) 匹配QQ号码
要求:6~10位,纯数字,首位不是零
编写:[1~9][0~9]{6,10}
(2) 匹配手机号
要求:11位,13或15或17开头
编写:1[357]\d{9}
(3) 匹配邮箱
要求:数字,字母(不区分大小写)+@+地址
编写:[\w\-]+@[a-zA-Z0-9]+([\.A-Za-z]{2,3}){1,2}
数据:25adada@163.com 584566@sina.com.cn
3.正则表达式在Java中的使用
package demo01;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class text03 {
/**
* 正则表达式的创建使用
* 整个模式的匹配,下一个序列的匹配
* .group()的简单使用,分组使用
*/
public static void main(String[] args) {
// 表达式对象,正则表达式( Java中单斜杠\改用双斜杠\\ )
Pattern p = Pattern.compile("\\w+");// 判断是不是字母数字下划线
// 创建Matcher对象,字符串
Matcher a = p.matcher("85693657");
Matcher b = p.matcher("233&&666");
boolean mark_1 = a.matches();// 尝试将整个字符序列与该模式匹配
boolean mark_2 = b.matches();
// .group() .group(0) 匹配整个表达式的子字符串
System.out.println(mark_1 + " " + a.group());// true,匹配85693657
System.out.println(mark_2);// false,不匹配233&&666
// System.out.println(mark_2+" "+b.group());
// 报错java.lang.IllegalStateException: No match found
Matcher c = p.matcher("253&&678");
boolean mark_3 = c.find();// 改方法扫描输入的序列,查找与该模式匹配的下一个序列
boolean mark_4 = c.find();
boolean mark_5 = c.find();
System.out.println(mark_3);// true,匹配253
// System.out.println(mark_3 + " " + c.group());
// 报错java.lang.IllegalStateException: No match found
System.out.println(mark_4);// true,匹配678
System.out.println(mark_5);// false,匹配253,678之后,没有再能匹配的
// .group(...)的分组使用
Pattern p_2 = Pattern.compile("([a-z]+)([0-9]+)");
Matcher d = p_2.matcher("aa111bb235cc698");
while (d.find()) {
System.out.println(d.group(0));// aa111,bb235,cc698
System.out.println(d.group(1));// aa,bb,cc
System.out.println(d.group(2));// 111,235,689
}
}
}
package demo01;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class text05 {
/**
* 正则表达式的使用
* 替换
* 分割
*/
public static void main(String[] args) {
//字符串的替换
Pattern p1 = Pattern.compile("[0-9]");
Matcher m1 = p1.matcher("aa1bbb253cc9d");
//将字符串里面的数字替换为*
String newStr =m1.replaceAll("*");
System.out.println(newStr);//aa*bbb***cc*d
//字符串的分割
String str="a,b,c";
String[] arrs=str.split(",");//按照逗号分割
System.out.println(Arrays.toString(arrs));//[a, b, c]
String str2="aa25AA369Cc2d";
String[] arrs2=str2.split("\\d+");//按照所有的数字分割
System.out.println(Arrays.toString(arrs2));//[aa, AA, Cc, d]
}
}