一、概述
正则表达式:用来描述或者匹配一系列符合某个语句规则的字符串
作用:1)校验字符串是否满足规则
2)在一段文本中查找满足要求的内容
二、正则表达式的常见形式
1.字符类(只匹配一个字符)
[a,b,c] | 只能a,b,c |
[^a,b,c] | 除了a,b,c以外的任何字符 |
[a-zA-Z] | 大小字母a~z及A~Z |
[a-d[m-p]] | a~d或m~p |
[a-z&&[def]] | a~z与d,e,f的交集,等价于:d或e或f |
[a-z&&[^bc]] | a~z与非bc的交集,等价于:a或d~z |
2.预定义字符(只匹配一个字符)
. | 任何字符 |
\d | 一个数字,等价于[0-9] |
\D | 非数字,等价于[^0-9] |
\s | 一个空白字符,等价于[\t\n\x\f\r] |
\S | 非空白符,等价于[^\s] |
\w | 包含数字、英文、下划线,等价于[a-zA-Z_0-9] |
\W | 表示不是由数字、英文、下划线组成 |
3.数量词
X? | X,零次或一次 |
X* | X,零次,一次或多次 |
X+ |
X,一次或多次 |
X{n} | X,正好n次 |
X{n,} | X,至少n次 |
X{n,m} | X,在n~m次 |
示例:借助正则表达式匹配的判断函数matches简单阐述
-
public boolean matches(String regex):返回true表示当前验证的字符串匹配正则表达式的描述
package ZhengZe;
public class RegexDemo {
public static void main(String[] args) {
// \ 转义字符:改变后面那个字符原本的含义
//若想要以字符串的形式打印一个双引号,需要转义字符改变"原本的含义(原本表示引用)
System.out.println("\""); //"
// .表示任意一个字符
System.out.println("你".matches("..")); //false
System.out.println("你a".matches("..")); //true
// \\d只能是任意的一位字符
// 第一个\表示转义字符;\d表示数字符
System.out.println("a".matches("\\d")); //false
System.out.println("3".matches("\\d")); //true
System.out.println("333".matches("\\d")); //false
// \\w只能是任意的一位单词字符 [a-zA-Z_0-9]
System.out.println("a".matches("\\w")); //true
System.out.println("3".matches("\\w")); //true
System.out.println("333".matches("\\w")); //false
// \\W 非单词字符
System.out.println("你".matches("\\W")); //true
//**********以上正则匹配只能校验单个字符**********//
// 必须是数字 字母 下划线,至少6位
System.out.println("a244_bcf".matches("\\w{6,}")); //true
System.out.println("a24f".matches("\\w{6,}")); //false
//必须是数字和字符,必须是4位
System.out.println("23dF".matches("[a-zA-Z0-9]{4}")); //true
System.out.println("23dF".matches("[\\w&&[^_]]{4}")); //true
}
}
三、正则表达式的应用
1.验证手机号码、座机号码、邮箱号码、身份证号的格式是否正确
package ZhengZe;
//验证手机号码、座机号码、邮箱号码、身份证号的格式是否正确
public class RegexDemo01 {
public static void main(String[] args) {
// 验证手机号码 13112345678 13712345667 139456790271
//将手机号码的格式分为三部分
//1)1 表示手机号码只能以1开头; 2)[3-9]表示第二位只能是3-9之间; 3)\\d{9}表示任意数字可以出现9次,也只能出现9次(一共只有11位)
String regex1 = "1[3-9]\\d{9}";
System.out.println("13112345678".matches(regex1)); //true
System.out.println("13712345667".matches(regex1)); //true
System.out.println("139456790271".matches(regex1)); //false
// 验证座机号码 020-2324242 02122442 0712-3242434 027-42424
//将手机号码的格式分为三部分
//1)区号 :0\\d{2,3},区号一定以0开头,从第二位开始可以是任意数字,0后面有2到3位
//2)- :-?, 次数:0或1次
//3)号码: [1-9]\\d{4,9}, 号码的第一位不能以0开头([1-9]),从第二位开始可以是任意数字,号码的总长度:5-10位(\\d{4,9})
String regex2 = "0\\d{2,3}-?[1-9]\\d{4,9}";
System.out.println("020-2324242".matches(regex2)); //true
System.out.println("02122442".matches(regex2)); //true
System.out.println("0712-3242434".matches(regex2)); //true
System.out.println("027-42424".matches(regex2)); //true
//验证邮箱号码 [email protected] [email protected] [email protected] [email protected]
//将邮箱的格式分为三部分
//1)@的左边 :\\w+,任意的数字字母下划线,出现一次就可以了
//2)@:必须出现,且只能出现一次
//3)@的左边 : .的左边[\\w&&[^_]]{2,6},任意的字母或者数字,总共出现2-6次(此时不能出现下划线);
// .的右边[a-zA-Z]{2,3},大小写字母只能出现2-3位
// (\\.[a-zA-Z]{2,3})括号表示分组,这一组出现1或2次
String regex3 = "\\w+@[\\w&&[^_]]{2,6}(\\.[a-zA-Z]{2,3}){1,2}";
System.out.println("[email protected]".matches(regex3)); //true
System.out.println("[email protected]".matches(regex3)); //true
System.out.println("[email protected]".matches(regex3)); //true
System.out.println("[email protected]".matches(regex3)); //true
//简单校验身份证号码
//18位,前17位任意数字,最后一位可以是大写或小写x(有以下三种表示方式)
//String regex4 = "[1-9]\\d{16}(\\d|X|x)";//最后一位用分组中“或”的关系表示
//String regex4 = "[1-9]\\d{16}[\\dXx]";
String regex4 = "[1-9]\\d{16}(\\d|(?i)x)";//(?i)x表示x不区分大写或者小写
System.out.println("41080119930225457x".matches(regex4)); //true
}
}
2.利用正则表达式爬取本地信息
有如下文本,按照要求爬取数据:
Java自从95年问世以来,经历了很多版本,母亲企业中用的最多的是Java8和Java11,
因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史的舞台。要求:找出里面的所有JavaXX
package Zhengze;
//利用正则表达式爬取本地信息
//Pattern类:表示正则表达式
//Matcher类:文本匹配器,按照正则表达式的规则去读取字符串,从头开始读取
// 在整个字符串去找符合匹配规则的子串
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexDemo02 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,母亲企业中用的最多的是Java8和Java11,"+
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史的舞台。";
//method1(str);//最初的编程思路,能够获得前两个JavaXX子串,要获得所有子串,使用循环语句
//1.获取正则表达式的对象
Pattern p = Pattern.compile("Java\\d{0,2}");
//2.获取文本匹配器的对象:m要在str中找符合p规则的字串
Matcher m = p.matcher(str);
//3.利用循环获取
while(m.find()) {
String s = m.group();
System.out.println(s);
}
}
private static void method1(String str) {
//1.获取正则表达式的对象
Pattern p = Pattern.compile("Java\\d{0,2}");//Java后附0~2位数字
//2.获取文本匹配器的对象:m--文本匹配器的对象;str--整个字符串;p--规则
//即 m要在str中找符合p规则的字串
Matcher m = p.matcher(str);
//拿着文本匹配器从头开始读取,寻找是否有满足规则的子串:如果没有,方法返回false;如果有,返回true,在底层记录子串的起始索引和结束索引+1
//而subString(起始索引,结束索引)这一方法包头不包尾,即对于子串[0,4],只存储索引0~3
boolean b = m.find();
//方法group:根据find方法记录的索引进行字符串的截取,把截取的子串进行返回
String s1 = m.group();
System.out.println(s1);
//3.第二次再次调用find方法的时候,会继续读取后面的内容
//读取到第二个满足要求的子串,方法会继续返回true,并把第二个子串的起始索引和结束索引+1,进行记录
b = m.find();
//第二次调用group方法,会根据find方法记录的索引再次截取子串
String s2 = m.group();
System.out.println(s2);
}
}
3.利用正则表达式爬去(所需格式的)网络信息
package Zhengze;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//利用正则表达式爬去网络信息(这是一个列有身份证号的网址)
//把链接:"https://www.qindaosou.com/baike/20210411825044.html"中所有的身份证号码全都爬取出来
public class RegexDemo03 {
public static void main(String[] args) throws IOException {
//创建一个网址对象
URL url = new URL("https://www.qindaosou.com/baike/20210411825044.html");
//连接上这个网址
//细节:保证网络是畅通的
URLConnection conn = url.openConnection();
//创建一个对象去读取网络中的数据
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
//获取正则表达式的对象pattern
String regex = "[1-9]\\d{17}";
Pattern pattern = Pattern.compile(regex);
//在读取的时候每次读一整行
while((line = br.readLine())!=null) {
//拿着文本匹配器的对象matcher按照pattern的规则去读取当前这一行信息
Matcher matcher = pattern.matcher(line);
while(matcher.find()) {
System.out.println(line);
}
//System.out.println(line);
}
br.close();
}
}
4.贪婪爬取和非贪婪爬取
有如下文本,按照要求爬取数据
Java自从95年问世以来,abbbbbbbaaaaaaaaaaa,经历了很多版本,目前企业中用的最多的是Java8和Java11.
因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史的舞台。
要求1:按照ab+的方式爬取ab,b尽可能多获取
要求2:按照ab+的方式爬取ab,b尽可能少获取
只写+和*表示贪婪匹配
+?非贪婪匹配
*?非贪婪匹配Java当中,默认的就是贪婪爬取;如果我们在数量词+/ * 的后面加上问号,那么此时就是非贪婪爬取
package Zhengze;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
//贪婪爬取和非贪婪爬取
//贪婪爬取:在爬取数据的时候尽可能的多获取数据;非贪婪爬取:在爬取数据的时候尽可能的少获取数据
public class RegexDemo04 {
public static void main(String[] args) {
String str = "java自从95年问世以来,abbbbbbbaaaaaaaaaaa"+
"经历了很多版本,目前企业中用的最多的是JAva8和JAVa11,"+
"因为这两个是长期支持版本,下一个长期支持版本是JAVA17,相信在未来不久Java17也会逐渐登上历史的舞台。";
String regex = "ab+"; //贪婪爬取
//String regex = "ab+?"; //非贪婪爬取
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while(m.find()) {
System.out.println(m.group());
}
}
}