文章目录
- 正则表达式
- 基本规则
- 字符类(只匹配一个字符)
- 预定义字符(只匹配一个字符)
- 数量词
- 练习
- 正则表达式插件
- 爬虫
- 利用正则表达式获取想要的内容
- 爬取网络信息
- 练习
- 有条件的爬取
- 贪婪爬取
- 非贪婪爬取
- 正则表达式在字符串中的使用
- 分组
- 捕获分组
- 正则表达式外部使用
- 非捕获分组
- 正则表达式忽略大小写
正则表达式
正则表达式的作用:
- 校验字符串是否满足规则
- 在一段文本中查找满足要求的内容
基本规则
字符类(只匹配一个字符)
表达式 | 说明 |
---|---|
[abc] | 只能是a,b或c |
[^abc] | 除了a,b,c之外的任何字符 |
[a-zA-Z] | a-z A-Z |
[a-d[m-p]] | a-d或m-p |
[a-z&&[def]] | a-z和def的交集,为:d、e、f |
public class test57 {
public static void main(String[] args) {
System.out.println("ab".matches("[abc]")); //false
System.out.println("ab".matches("[abc][abc]")); //true
//一个&在正则表达式中是一个符号
System.out.println("&".matches("[a-z&[abc]]")); //true
System.out.println("0".matches("a-z&&[abc]")); //false 0不在a-z与abc的交集里面
}
}
预定义字符(只匹配一个字符)
表达式 | 说明 |
---|---|
. | 任何字符 |
\d | 一个数字[0-9] |
\D | 非数字 |
\s | 一个空白字符[\t\n\x0B\f\r] |
\S | 非空白字符 |
\w | [a-zA-Z_0-9]英文、数字、下划线 |
\W | [^\w] |
\ 转义字符,改变后面字符的含义
\ 前面的\是一个转义字符,把后面的\变成一个普通的无含义字符(路径)
public class test57 {
public static void main(String[] args) {
// \ 转义字符,改变后面字符的含义
// \\ 前面的\是一个转义字符,把后面的\变成一个普通的无含义字符(路径)
System.out.println("\""); //"
System.out.println("3".matches("\\d")); //true
System.out.println("2333".matches("\\d\\d\\d\\d")); //true
}
}
数量词
表达式 | 说明 |
---|---|
X? | X,1次或0次 |
X* | X,0次或多次 |
X+ | X,1次或多次 |
X{n} | X,正好n次 |
X{n,} | X,至少n次 |
X{n,m} | X,至少n但不超过m次 |
练习
需求1:
请编写正则表达式验证用户输入的手机号码是否满足要求
请编写正则表达式验证用户输入的邮箱号是否满足要求
请编写正则表达式验证用户输入的电话号码是否满足要求
验证手机号码 13112345678 13712345667 13945679027 139456790271
验证座机电话号码 020-2324242 02122442 027-42424 0712-3242434
验证邮箱号码 3232323@qq.com zhangsan@itcast.cnn dlei0009@163.com dlei0009@pci.com.cn
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test9 {
public static void main(String[] args) {
while(true){
System.out.println("-----------请输入手机号/邮箱号/电话号-----------");
Scanner sc=new Scanner(System.in);
String str=sc.nextLine();
if(str.equals("exit")){
break;
}
System.out.println("-------------------验证中--------------------");
System.out.println("-----------------验证结果为-------------------");
//手机号:1[3-9]\\d{9}
//第一部分:1 表示手机号码只能以1开头
//第二部分:[3-9] 表示手机号码第二位只能是3-9之间的
//第三部分:\\d{9} 表示任意数字可以出现9次,也只能出现9次
//邮箱号:\\w+@[\\w&&[^_]]{2,6}(\\.[A-Za-z]{2,3}){1,2}
//第一部分:@的左边 \\w+
// 任意的字母数字下划线,至少出现一次就可以了
//第二部分:@ 只能出现一次
//第三部分:
// 3.1 .的左边[\\w&&[^_]]{2,6}
// 任意的字母加数字,总共出现2-6次(此时不能出现下划线)
// 3.2 . \\.
// 3.3 大写字母,小写字母都可以,只能出现2-3次[a-zA-Z]{2,3}
// 我们可以把3.2和3.3看成一组,这一组可以出现1次或者两次
//电话号:0\\d{2,3}-?[1-9]\\d{4,9}
//一:区号@\\d{2,3}
// 0:表示区号一定是以0开头的
// \\d{2,3}:表示区号从第二位开始可以是任意的数字,可以出现2到3次。
//二:- ?表示次数,日次或一次
//三:号码 号码的第一位也不能以日开头,从第二位开始可以是任意的数字,号码的总长度:5-10位
String regex="(1[3-9]\\d{9})|(\\w+@[\\w&&[^_]]{2,6}(\\.[A-Za-z]{2,3}){1,2})|(0\\d{2,3}-?[1-9]\\d{4,9})";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
if(matcher.find()){
System.out.println("-----------------验证成功!-------------------");
}else{
System.out.println("-----------验证失败!提示:输入错误!------------");
}
}
}
}
需求2:
请编写正则表达式验证用户名是否满足要求。要求:大小写字母,数字,下划线一共4-16位
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test10 {
public static void main(String[] args) {
//大小写字母,数字,下划线一共4-16位
Scanner sc=new Scanner(System.in);
String regex="\\w{4,16}";
Pattern pattern= Pattern.compile(regex);
while(true){
String str=sc.nextLine();
if(str.equals("exit")){
break;
}
Matcher matcher=pattern.matcher(str);
System.out.println(matcher.find());
}
}
}
需求3:
请编写正则表达式验证身份证号码是否满足要求。
简单要求:18位,前17位任意数字,最后一位可以是数字可以是大写或小写的x
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test11 {
public static void main(String[] args) {
//18位,前17位任意数字,最后一位可以是数字可以是大写或小写的x
Scanner sc=new Scanner(System.in);
String regex="\\d{17}(\\d|X|x)";
Pattern pattern=Pattern.compile(regex);
while (true){
String str=sc.nextLine();
if(str.equals("exit")){
break;
}
Matcher matcher=pattern.matcher(str);
System.out.println(matcher.find());
}
}
}
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test11 {
public static void main(String[] args) {
//18位,前17位任意数字,最后一位可以是数字可以是大写或小写的x
Scanner sc=new Scanner(System.in);
String regex="\\d{17}[\\dXx]";
Pattern pattern=Pattern.compile(regex);
while (true){
String str=sc.nextLine();
if(str.equals("exit")){
break;
}
Matcher matcher=pattern.matcher(str);
System.out.println(matcher.find());
}
}
}
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test11 {
public static void main(String[] args) {
//18位,前17位任意数字,最后一位可以是数字可以是大写或小写的x
Scanner sc=new Scanner(System.in);
String regex="(?i)\\d{17}[\\dx]";
Pattern pattern=Pattern.compile(regex);
while (true){
String str=sc.nextLine();
if(str.equals("exit")){
break;
}
Matcher matcher=pattern.matcher(str);
System.out.println(matcher.find());
}
}
}
复杂要求:按照身份证号码的格式严格要求。
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test12 {
public static void main(String[] args) {
//410801 1993 02 28 457x
//前面6位:省份,市区,派出所等信息,第一位不能是0,后面5位是任意数字 [1-9]\\d{5}
//年的前半段: 18 19 20 (18|19|20)
//年的后半段: 任意数字出现两次 \\d{2}
//月份: 01~ 09 10 11 12 0[1-9]|1[0-2]
//日期: 01~09 10~19 20~29 30 31 0[1-9]|[12]\\d|[3][01]
//后面四位: 任意数字出现3次 最后一位可以是数字也可以是大写x或者小写x \\d{3}[\\dXx]
Scanner sc=new Scanner(System.in);
String regex="[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|[3][01])\\d{3}[\\dXx]";
Pattern pattern= Pattern.compile(regex);
while(true){
String str= sc.nextLine();
if(str.equals("exit")){
break;
}
Matcher matcher=pattern.matcher(str);
System.out.println(matcher.find());
}
}
}
正则表达式插件
爬虫
利用正则表达式获取想要的内容
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test1 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,"
+ "因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
Pattern pattern=Pattern.compile("Java\\d{0,2}"); //正则表达式对象
Matcher matcher=pattern.matcher(str); //文本匹配器对象
while(matcher.find()){ //是否有满足规则的子串,如果为true,底层会记录子串的起始索引和结束索引+1
System.out.println(matcher.group()); //返回满足规则的子串
}
}
}
爬取网络信息
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;
public class test2 {
public static void main(String[] args) throws IOException {
URL url=new URL("https://520zuowens.com/xiaoxue/1122109.html"); // 爬取信息的网址
URLConnection urlConnection= url.openConnection(); // 建立连接
BufferedReader br=new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
Pattern pattern=Pattern.compile("[1-9]\\d{17}"); // 正则表达式对象
String str;
while((str= br.readLine())!=null){
Matcher matcher=pattern.matcher(str);
while (matcher.find()){
System.out.println(matcher.group());
}
}
br.close();
}
}
练习
需求:
把下面文本中的座机电话,邮箱,手机号,热线都爬取出来。
来学习Java,
手机号:18512516758,18512508907,
联系邮箱:boniu@itcast.cn,
座机电话:01036517895,010-98951256
邮箱:bozai@itcast.cn,
热线电话:400-618-9090 ,400-618-4000,4006184000,4006189090。
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test3 {
public static void main(String[] args) throws IOException {
String str="来学习Java,\n" +
"手机号:18512516758,18512508907.\n" +
"联系邮箱:boniu@itcast.cn,\n" +
"座机电话:01036517895,010-98951256\n" +
"邮箱:bozai@itcast.cn,\n" +
"热线电话:400-618-9090 ,400-618-4000,4006184000,4006189090。\n";
byte[] bytes=str.getBytes();
InputStream inputStream=new ByteArrayInputStream(bytes);
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
// 手机号的正则表达式:1[3-9]\\d{9}
// 邮箱的正则表达式:\\w+@[\\w&&[^_]]{2,6}.[A-Za-z]{2,3}
// 座机电话的正则表达式:0\\d{2,3}-?[1-9]\\d{4,9}
// 热线电话正则表达式:400-?\\d{3}-?\\d{4}
String regex="(1[3-9]\\d{9})|(\\w+@[\\w&&[^_]]{2,6}.[A-Za-z]{2,3})|(0\\d{2,3}-?[1-9]\\d{4,9})|(400-?\\d{3}-?\\d{4})";
Pattern pattern=Pattern.compile(regex);
String str1;
while((str1=br.readLine())!=null){
Matcher matcher=pattern.matcher(str1);
while (matcher.find()){
System.out.println(matcher.group().toString());
}
}
}
}
有条件的爬取
需求:
有如下文本,按要求爬取数据。
Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11,因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台。
需求1:
爬取版本号为8,11.17的Java文本,但是只要Java,不显示版本号。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11," +
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex="Java(?=8|11|17)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println(matcher.group());
}
}
}
忽略java大小写:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是JAva8和Java11," +
"因为这两个是长期支持版本,下一个长期支持版本是JaVa17,相信在未来不久JavA17也会逐渐登上历史舞台";
String regex="((?i)Java)(?=8|11|17)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println(matcher.group());
}
}
}
需求2:
爬取版本号为8,11,17的Java文本。正确爬取结果为:Java8 Java11 Java17 Java17
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11," +
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex="Java(8|11|17)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println(matcher.group());
}
}
}
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11," +
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex="Java(?:8|11|17)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println(matcher.group());
}
}
}
需求3:
爬取除了版本号为8,11,17的Java文本。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test4 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,经历了很多版本,目前企业中用的最多的是Java8和Java11," +
"因为这两个是长期支持版本,下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex="Java(?!8|11|17)";
Pattern pattern=Pattern.compile(regex);
Matcher matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println(matcher.group());
}
}
}
贪婪爬取
只写+和表示贪婪匹配,如果在+和后面加问号表示非贪婪爬取
+? 非贪婪匹配
*? 非贪婪匹配
贪婪爬取:在爬取数据的时候尽可能的多获取数据
非贪婪爬取:在爬取数据的时候尽可能的少获取数据
举例:
如果获取数据:ab+
贪婪爬取获取结果:abbbbbbbbbbbb
如果获取数据:ab+?
非贪婪爬取获取结果:ab
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test5 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaa" +
"经历了很多版木,目前企业中用的最多的是]ava8和]ava11,因为这两个是长期支持版木。" +
"下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex = "ab+"; // 贪婪爬取
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
非贪婪爬取
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test5 {
public static void main(String[] args) {
String str = "Java自从95年问世以来,abbbbbbbbbbbbaaaaaaaaaaaaaaaaaa" +
"经历了很多版木,目前企业中用的最多的是]ava8和]ava11,因为这两个是长期支持版木。" +
"下一个长期支持版本是Java17,相信在未来不久Java17也会逐渐登上历史舞台";
String regex = "ab+?"; // 非贪婪爬取
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
正则表达式在字符串中的使用
public class test6 {
public static void main(String[] args) {
String str="cjm是猪dqwefqwfqwfwq12312cjm是猪dqwefqwfqwfwq12312cjm是猪";
// 方法底层也会创建文本解析器的对象
// 从头开始读,满足条件的用第二个参数替换
String result=str.replaceAll("[\\w&&[^_]&&[^cjm]]+"," !!!cjm是sqd的猪!!! ");
System.out.println(result);
}
}
运行结果:cjm是猪 !!!cjm是sqd的猪!!! cjm是猪 !!!cjm是sqd的猪!!! cjm是猪
public class test6 {
public static void main(String[] args) {
String str="cjm是猪dqwefqwfqwfwq12312cjm是猪dqwefqwfqwfwq12312cjm是猪";
String[] result=str.split("[\\w&&[^_]&&[^cjm]]+");
for(int i=0;i<result.length;i++){
System.out.println(result[i]);
}
}
}
运行结果:
cjm是猪
cjm是猪
cjm是猪
分组
捕获分组
可以获取每组中的内容反复使用。
需求1:判断一个字符串的开始字符和结束字符是否一致?只考虑一个字符
举例:a123a b456b 17891 &abc& a123b(false)
public class test7 {
public static void main(String[] args) {
// \\1表示第一个分组
String regex="(.).+\\1";
System.out.println("a123a".matches(regex));
System.out.println("b456b".matches(regex));
System.out.println("17891".matches(regex));
System.out.println("&abc&".matches(regex));
System.out.println("a123b".matches(regex));
}
}
需求2:判断一个字符串的开始部分和结束部分是否一致?可以有多个字符
举例:abc123abc b456b 123789123 &!@abc&!@ abc123abd(false)
public class test7 {
public static void main(String[] args) {
// \\1表示第一个分组
String regex="(.+).+\\1";
System.out.println("abc123abc".matches(regex));
System.out.println("b456b".matches(regex));
System.out.println("123789123".matches(regex));
System.out.println("&!@abc&!@".matches(regex));
System.out.println("abc123abd".matches(regex));
}
}
需求3:判断一个字符串的开始部分和结束部分是否一致?开始部分内部每个字符也需要一致
举例:aaa123aaa bbb456bbb 111789111 &&abc&&
public class test7 {
public static void main(String[] args) {
// (.):把首字母看做一组
// \\2:把首字母拿出来再次使用
// *:作用于\\2,表示后面重复的内容出现0次或多次
String regex="((.)\\2*).+\\1";
System.out.println("aaa123aaa".matches(regex));
System.out.println("bbb456bbb".matches(regex));
System.out.println("111789111".matches(regex));
System.out.println("&&abc&&".matches(regex));
}
}
正则表达式外部使用
需求:
将字符串:我要学学编编编编程程程程程程。
替换为:我要学编程
public class test8 {
public static void main(String[] args) {
String str = "我要学学编编编编程程程程程程";
// (.)表示把重复内容的第一个字符看做一组
// \\1表示第一字符再次出现
// + 至少一次
// $1 表示把正则表达式中第一组的内容,再拿出来用
String result=str.replaceAll("(.)\\1+","$1");
System.out.println(result);
}
}
非捕获分组
使用非捕获分组的数据不占组号。
正则表达式忽略大小写
(?i) :表示忽略后面数据的大小写
//忽略abc的大小写
String regex = "(?i)abc";
//a需要一模一样,忽略bc的大小写
String regex = "a(?i)bc";
//ac需要一模一样,忽略b的大小写
String regex = "a((?i)b)c";