一 正则表达式入门
1 极速体验正则表达式威力
package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
体验正则表达式的威力,给我们文本处理带来哪些便利
public class Regexp_ {
public static void main(String[] args) {
String context="1994年6、7月间,在经历了一场历时三天的讨论之后,团队决定再一次改变了努力的目标,这次他们决" +
"定将该技术应用于万维网。他们认为随着Mosaic浏览器的到来,因特网正在向同样的高度互动的远景演变,而这一" +
"远景正是他们在有线电视网中看到的。作为原型,帕特里克·诺顿写了一个小型万维网浏览器WebRunner。 [8] \n" +
"1995年,互联网的蓬勃发展给了Oak机会。业界为了使死板、单调的静态网页能够“灵活”起来,急需一种软件技术来" +
"开发一种程序,这种程序可以通过网络传播并且能够跨平台运行。于是,世界各大IT企业为此纷纷投入了大量的人力、物" +
"力和财力。这个时候,Sun公司想起了那个被搁置起来很久的Oak,并且重新审视了那个用软件编写的试验平台,由于它是" +
"按照嵌入式系统硬件平台体系结构进行编写的,所以非常小,特别适用于网络上的传输系统,而Oak也是一种精简的语言," +
"程序非常小,适合在网络上传输。Sun公司首先推出了可以嵌入网页并且可以随同网页在网络上传输的Applet(Applet是一种" +
"将小程序嵌入到网页中进行执行的技术),并将Oak更名为Java。5月23日,Sun公司在Sun world会议上正式发布Java和Ho" +
"tJava浏览器。IBM、Apple、DEC、Adobe、HP、Oracle、Netscape和微软等各大公司都纷纷停止了自己的相关开发项目," +
"竞相购买了Java使用许可证,并为自己的产品开发了相应的Java平台。 [9-10] \n" +
"1996年1月,Sun公司发布了Java的第一个开发工具包(JDK 1.0),这是Java发展历程中的重要里程碑,标志着Java成为一" +
"种独立的开发工具。9月,约8.3万个网页应用了Java技术来制作。10月,Sun公司发布了Java平台的第一个即时(JIT)编译器。";
//首先先获得一个正则表达式的对象
//Pattern pattern=Pattern.compile("[a-zA-Z]+"); //获取文中所有单词
//Pattern pattern = Pattern.compile("[0-9]+"); //获取文中所有数字
Pattern pattern = Pattern.compile("[0-9]+|[a-zA-Z]+"); //获取文中所有数字加单词
//Pattern pattern = Pattern.compile("\\d\\d\\d\\d"); 其中一个\\d代表一个0-9的任意数字
//创建一个匹配器对象 就是按照一个正则表达式的要求去文本中查找
Matcher matcher = pattern.matcher(context);
//通过循环查找所有满足条件的字符串
while (matcher.find()){
//如果找到,返回true 没有则false
System.out.println(matcher.group()); //默认值就是0 可写可不写
}
}
}
二 为什么要学正则表达式
三 正则表达式基本介绍
1 介绍
2 正则表达式底层实现🚩🚩
package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
分析java的正则表达式的底层实现(重要.)
public class RegTheory {
public static void main(String[] args) {
String content = "1998年12月8日,第二代Java平台的企业版J2EE发布。" +
"1999年6月,Sun公司发布了第二代Java平台(简称为Java2)的3个版本:" +
"J2ME(Java2 Micro Edition,Java2平台的微型版),应用于移动、无线及" +
"有限资源的环境;J2SE(Java 2 Standard Edition,Java 2平台的标" +
"准版),应用于桌面环境;J2EE(Java 2Enterprise Edition,Java 2平台" +
"的企业版),应用于基于Java的应用服务器。Java 2平台的发布,是Java发展" +
"过程中最重要的一个里程碑,标志着Java的应用开始普及。";
//String regStr = "\\d\\d\\d\\d";
String regStr = "(\\d\\d)(\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
/**
* matcher.find() 完成的任务
* 1. 根据指定的规则,定位满足规则的子字符串(比如1998)
* 2. 找到后,将子字符串的开始的索引记录到matcher对象的属性int[] groups;
* group[0] = 0, 把该子字符串的结束的索引+1的值记录到 groups[1] = 4;
* 3. 同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4 即下次执行find时 就从4开始匹配
*
* matcher.find() 完成的任务
* 1. 根据指定的规则,定位满足规则的子字符串(比如(19)(98))
* 2. 找到后,将子字符串的开始的索引记录到matcher对象的属性int[] groups;
* 2.1 group[0] = 0, 把该子字符串的结束的索引+1的值记录到 groups[1] = 4;
* 2.2 记录1组的()匹配到的字符串 groups[2] = 0 groups[3] = 2
* 2.3 记录2组的()匹配到的字符串 groups[4] = 2 groups[5] = 4
* 3. 同时记录 oldLast 的值为 子字符串的结束的 索引+1的值即4 即下次执行find时 就从4开始匹配
*/
while (matcher.find()) {
System.out.println("找到:" + matcher.group(0));
System.out.println("找到:" + matcher.group(1));//表示匹配到的子字符串的第一组子串
System.out.println("找到:" + matcher.group(2));//表示匹配到的子字符串的第二组子串
}
}
}
四 正则表达式语法
1 元字符(转义符)
需要用到转移符号的字符有以下:. + ( ) $ [ ] ^ { }
package com.hspedu.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
演示转义字符的使用
public class RegExp02 {
public static void main(String[] args) {
String content = "abc$(a.bc(123(";
//匹配( = \\(
//匹配. = \\.
String regStr = "\\."; //如果不加前面两个\\则代表匹配所有的字符
//String regStr = "ddd";//在每个d前面加\\,则代表匹配3个连续任意数字,不加则匹配3个d
//String regStr = "\\d{3}";//如果不加前面两个\\则代表匹配3个d,加上则匹配三个连续任意数字
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到" + matcher.group(0));
}
}
}
(1)限定符
用于指定其前面的字符和组合项连续出现多少次。
public static void main(String[] args) {
String content = "11111111aaaaaaahello";
//String regStr = "a{3}";// 匹配 aaa
//String regStr = "1{4}";// 匹配 1111
//String regStr = "\\d{2}";// 匹配 两位任意数字字符
//Java默认匹配多的(贪婪匹配)
//String regStr = "a{3,4}";// 匹配 aaa 或 aaaa(优先)
//String regStr = "1{4,5}";// 匹配 1111 或 11111(优先)
//String regStr = "\\d{2,5}";// 匹配 2位数 或 3,4,5 实际 sout (找到 11111 (换行) 找到 111)
//String regStr = "1+";// 匹配 1个1 或 多个1
//String regStr = "\\d+";// 匹配 1个数字 或 多个数字
//String regStr = "1*"; // 匹配0个1或者多个1
String regStr = "a1?";// 匹配 a 或 a1
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
}
}
(2)选择匹配符
在匹配某个字符串的时候是选择性的,即:既可以匹配这个,又可以匹配那个,这时候你需要用到选择匹配符号 。
public static void main(String[] args) {
String content = "hanshunping|韩|寒冷";
String regStr = "hanshunping";
//String regStr = "韩";
//String regStr = "寒冷";
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到" + matcher.group(0));
}
}
(3)分组组合符
a 常用分组
public static void main(String[] args) {
String content = "hanshunping s7789 nn1189han";
//String regStr = "(\\d\\d)(\\d\\d)";//匹配四个数组的字符串(7789)(1189)
//String regStr = "(\\d\\d)(\\d)(\\d)";
/**
* 找到 7789
* 第一个分组 77
* 第二个分组 8
* 第三个分组 9
* 找到 1189
* 第一个分组 11
* 第二个分组 8
* 第三个分组 9
*/
String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
/**
* 找到 7789
* 第一个分组[编号] 77
* 第二个分组[编号] 89
* 找到 1189
* 第一个分组[编号] 11
* 第二个分组[编号] 89
*/
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
//System.out.println("第一个分组 " + matcher.group(1));
System.out.println("第一个分组[编号] " + matcher.group("g1"));
//System.out.println("第二个分组 " + matcher.group(2));
System.out.println("第二个分组[编号] " + matcher.group("g2"));
//System.out.println("第三个分组 " + matcher.group(3));
}
}
b 特别分组
public static void main(String[] args) {
String content = "hello韩顺平教育 Jack韩顺平老师 韩顺平同学hello";
//找到 韩顺平教育 、 韩顺平老师 、 韩顺平同学
//String regStr = "韩顺平(?:教育|老师|同学)";//不能group(1)
//找到 韩顺平教育中的韩顺平 韩顺平老师中的韩顺平
//String regStr = "韩顺平(?=教育|老师)";
//找到 不是韩顺平教育中的韩顺平 不是韩顺平老师中的韩顺平
String regStr = "韩顺平(?!教育|老师)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
//非捕获分组 不能使用group(1)
System.out.println("找到 " + matcher.group(0));
}
}
(4)字符匹配符
应用实例
public static void main(String[] args) {
String content = "a11c8abcABCCy @";
//String regStr = "[a-z]";//匹配 a-z之间任意一个字符
//String regStr = "[A-Z]";//匹配 A-Z之间任意一个字符
//String regStr = "abc";//匹配 abc 字符串[默认区分大小写]
//String regStr = "(?i)abc";//匹配 abc 字符串[不区分大小写]
//String regStr = "[0-9]";//匹配 0-9 之间任意一个字符
//String regStr = "[^a-z]";//匹配 不在 a-z之间任意一个字符
//String regStr = "[^0-9]";//匹配 不在 0-9之间任意一个字符
//String regStr = "[abcd]";//匹配 在 abcd中任意一个字符
//String regStr = "\\D";//匹配 不在 0-9的任意一个字符
//String regStr = "\\w";//匹配 大小写英文字母, 数字,下划线
//String regStr = "\\W";//匹配 等价于 [^a-zA-Z0-9_]
//\\s 匹配任何空白字符(空格,制表符等)
//String regStr = "\\s";
//\\S 匹配任何非空白字符 ,和s刚好相反
//String regStr = "\\S";
//. 匹配出 \n 之外的所有字符,如果要匹配.本身则需要使用 \\.
String regStr = ".";
//说明
//1. 当创建Pattern对象时,指定 Pattern.CASE_INSENSITIVE, 表示匹配是不区分字母大小写.
Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到" + matcher.group(0));
}
}
非贪婪匹配
public static void main(String[] args) {
String content = "hello111111 ok";
//String regStr = "\\d+"; //默认是贪婪匹配
String regStr = "\\d+?"; //非贪婪匹配
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到" + matcher.group(0));
}
}
(5)定位符
定位符,规定要匹配的字符串出现的位置,比如在字符串的开始还是结束的位置,这个也是相当有用的。
public static void main(String[] args) {
//String content = "123anj-556abc-945BGh";
//String content = "123-ljj";
String content = "hanshunping sphan nnhan";
//String regStr = "^[0-9]+[a-z]*";// 找到123anj
//String regStr = "^[0-9]+\\-[a-z]+$";// 找到123-ljj
//String regStr = "^[0-9]+\\-[a-z]+$";// 找到123-ljj
//String regStr = "han\\b";// 找到 han (sphan) 找到 han (nnhan)
String regStr = "han\\B";// 找到 han (hanshunping)
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
}
}
五 正则表达式三个常用类
1 Pattern类
(1)matches方法
用于整体匹配,在验证输入的字符串是否满足条件时使用。
public static void main(String[] args) {
String content = "hello abc hello, 韩顺平教育";
//String regStr = "hello";
String regStr = "hello.*";
boolean matches = Pattern.matches(regStr, content);
System.out.println("整体匹配=" + matches);
}
2 Matcher类
public static void main(String[] args) {
String content = "hello edu jack hspedutom hello smith hello hspedu hspedu";
String regStr = "hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("=================");
System.out.println(matcher.start());
System.out.println(matcher.end());
System.out.println("找到" + content.substring(matcher.start(), matcher.end()));
}
//整体匹配方法,常用于,去校验某个字符串是否满足某个规则
System.out.println("整体匹配=" + matcher.matches());
//完成如果content 有 hspedu 替换成 韩顺平教育
regStr = "hspedu";
pattern = Pattern.compile(regStr);
matcher = pattern.matcher(content);
//注意:返回的字符串才是替换后的字符串 原来的 content 不变化
String newContent = matcher.replaceAll("韩顺平教育");
System.out.println("newContent=" + newContent);
System.out.println("content=" + content);
}
3 PatternSyntaxException类
六 分组、捕获、反向引用
public static void main(String[] args) {
String content = "hello hspedu11111 hello22 12345-111222333";
//找到两个连续相同的数字
//String regStr = "(\\d)\\1";
//找到五个连续相同的数字
//String regStr = "(\\d)\\1{4}";
//找到个位与千位相同 十位与百位相同的数字
//String regStr = "(\\d)(\\d)\\2\\1";
//找到以下格式 "五位数-九位数连续每三位相同(例如:12345-111222333)"
String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println("找到 " + matcher.group(0));
}
}
七 String类中使用正则表达式
1 替换功能
public static void main(String[] args) {
String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其\" + " +
"获得了Apple公司Mac OS X的工业标准的支持。2001年9月24日,J2EE1.3发布。" +
"2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升";
//使用正则表达式方式,将 JDK1.3 和 JDK1.4 替换成JDK
content = content.replaceAll("JDK1.3|JDK1.4", "JDK");
System.out.println(content);
}
2 判断功能
public static void main(String[] args) {
String content = "13888889999";
if (content.matches("1(38|39)d{8}")) {
System.out.println("验证成功");
} else {
System.out.println("验证失败");
}
}
3 分割功能
public static void main(String[] args) {
//要求按照 # 或者 - 或者 ~ 或者 数字 来分割
System.out.println("===================");
content = "hello#abc-jack12smith~北京";
String[] split = content.split("#|-|~|\\d+");
for (String s : split) {
System.out.println(s);
}
}
八 正则应用案例
public static void main(String[] args) {
String content = "13588889999";
//汉字
//String regStr = "^[\u0391-\uffe5]+$";
//邮政编码
//要求:1.是1-9开头的一个六位数. 比如:123890
// 2.
// 3.
//String regStr = ^[1-9]\\d{5}$;
//QQ号码
//要求 是1-9开头的一个(5位数-10位数) 比如 12389 , 1345687 , 187698765
//String regStr = "^[1-9]\\d{4,9}$";
//手机号码
//要求 必须以13,14,15,18 开头的11位数 , 比如 13588889999
String regStr = "^1[3|4|5|8]\\d{9}$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()) {
System.out.println("满足格式");
} else {
System.out.println("不满足格式");
}
}
public static void main(String[] args) {
//String content = "https://www.bilibili.com/video/BV1fh411y7R8?";
String content = "https://blog.csdn.net/wthsoso/article/details/136381971";
/** ((http|https)://)开始部分
* ([\w-]+\.)+[\w-]+ 匹配 www.bilibili.com
* (\/[\w-?=&/%.#]*)? 匹配 /video/BV1fh411y7R8?p=894&vd_source=a8223634aa8a190c7233a2dc3f8a15e3
* []里面的元素相当于一个集合
* 如果查找 "(去掉http)edu.metastudy.vip/mt/official/pc/mxmt-ksjhdj"
* regStr = "^((http|https)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
*/
String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("true");
} else {
System.out.println("false");
}
}
public static void main(String[] args) {
String content = "我....我要....学学学学....编程java!";
//去掉所有的 .
Pattern pattern = Pattern.compile("\\.");
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
System.out.println("content=" + content);
//去掉重复的字 (.)查找任意的字符 \\1反向引用出'(.)'的内容 +指重复多次 $1表示重复字符替换为1个
//如果要替换ABAB型 例如"我要我要" 使用(..)\\1+
content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
System.out.println("content=" + content);
}