简单笔记
快速入门和简介
快速入门
package com.scy;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class pattern {
public static void main(String[] args) {
String content = "Java是世界上使用最广泛的编程语言之一。Java最初由Sun Microsystems在1990年代开发," +
"用于开发从Web应用程序到移动应用程序到批处理应用程序的所有内容。Java最初是一种纯粹的面向对象的语言," +
"但现在已经发展成为一种多范例语言,可以高度适应任何情况。" +
"拥有庞大的开发人员社区和支持库,Java是开发几乎所有类型的应用程序的理想选择。";
//提取文章中的所有英文单词
//1.传统方法:遍历
//2.正则表达式匹配
//1.先创建一个Pattren对象,模式对象,可以理解为一个正则表达式对象
Pattern pattern = Pattern.compile("[a-zA-z]+");
//2.创建一个匹配器对象
//理解:就是matcher匹配器按照pattern(模式/样式)到content文本中区匹配
//找到返回true,否则返回false
Matcher matcher = pattern.matcher(content);
//3.可以开始循环匹配
while (matcher.find()){
//匹配内容,文本,放到m.group(0)
System.out.println(matcher.group(0));
}
}
}
正则表达式底层
@Test
public void test01(){
String str = "1998年12月8日,第二代Java平台的企业版32EE发布。1999年6月,Sun公司发布了"+
"第二代Java平台(简称为Java2)的3个版本:J2NE (Java2 Nicro Edition,Java2平台的微型版),应用于移动、无线及有限资源的环境;J2SE (Java 2 Standard Edition,Java 2平台的”+标准版)," +
"应用于桌面环境;J2EE (Java 2Enterprise Edition,Java 2平台的企业版)," +
"应+用3443于基于Java的应用服务器。Java 2平台的发布,是Java发展过程中最重要的一个"+
"里程碑,标志着Java的应用开始普及9889;";
//目标:匹配所有四个数字
//1.\\d 表示任意一个数字
String regStr = "\\d\\d\\d\\d";
//2.创建模式对象 = 正则表达式对象
Pattern pattren = Pattern.compile(regStr);
//3.创建匹配器
//说明:创建匹配器matcher,按照正则表达式的规则,去匹配content字符串
Matcher matcher = pattren.matcher(str);
//4.开始匹配
while(matcher.find()){
System.out.println(matcher.group(0));
}
}
/*
* 1.根据指定的规则,定位满足规则的子字符串(比如1999)
* 2.找到后,将子字符串的开始的索引记录到 matcher对象的属性 int[] groups;*groups[0] = 31 把该子字符串的结束的索引+1的值记录到groups[1] = 35
* 3.同时记录oldLast的值为子字符串的结束的索引+1的信即35,即下次执行find时,就从35开始匹配
* matcher.group(0)分析
* public String group(int group) {
* if (first < 0)
* throw new IllegalStateException("No match found");
* if (group < 0 || group > groupCount())
* throw new IndexOutOfBoundsException("No group " + group);
* if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
* return null;
* return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
* }
* 1.根据 groups[0]=轮和groups[1]=4 的记录的位置,从content开始截取子字符串返回
* 就是[0,4)包含0但是不包含索引为4的位置
*/
group()里面的参数
while(matcher.find()){
//1.如果正则表达式有(〕即分组
//2.取出匹配的字符串规则如下
//3. group(0)表示匹配到的子字符串
//4. group(1)表示匹配到的子字符串的第一组字串
//5. group(2)表示匹配到的子字符串的第2组字串
//6. ...但是分组的数不能越界。
System.out.println(matcher.group(0));
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
}
分组(\d\d)(\d\d)
什么是分组,比如(\d\d)(\d\d),正则表达式中有(〕表示分组,第1个()表示第1组,第2个()表示第2组...*
1.根据指定的规则,定位满足规则的子字符串(比如(19)(98))
2.找到后,将子字符串的开始的索引记录到 matcher对象的属性int[] groups;*
2.1 groups[0] = 0,把该子字符串的结束的索引+1的值记录到 groups[1] = 4
2.2记录1组()匹配到的字符串groups[2] = 0 groups[3] = 2
2.3记录2组()匹配到的字符串 groups[4] = 2 groups[5] = 3
正则语法
元字符-转义号 \\
符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错的。
案例:用$去匹配“abc$(”会怎样)
需要用到转义符号的字符有以下 . * + ( ) $ / \ ? [ ] ^ {}
元字符-字符匹配符
Java的字符匹配符默认区分大小写,改变方式:
1.通过(?i)改为不区分大小写。例如(?i)abc可以匹配abc或ABC,a(?i)bc可以匹配bc或BC,a(?)b)c可以匹配b或B
2.通过设置参数不区分大小写。例如Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);
@Test
public void test02(){
String context = "a1123";
String regStr = "[a-z]";
//String regStr = "abc"; //匹配abc,不忽略大小写
//String regStr = "(?i)abc"; //匹配abc,全忽略大小写
//String regStr = "a(?i)bc"; //匹配abc,bc忽略大小写
//String regStr = "a((?i)b)c";
//String regStr = "[A-Z]";
//String regStr = "[^a-z]{2}";//连续两个不在a-z之间的数
//String regStr = "[abc]{2}";//连续两个不在abc之间的
//String regStr = "\\D";//不在0-9之间
//String regStr = "\\w";//匹配任意英文字符,数字和下划线,相当于[a-zA-z0-9_]
//String regStr = "\\s";//匹配空白字符
//String regStr = "..";//匹配除\n以外的所有字符,如果匹配.本身就用\\.
Pattern pattern = Pattern.compile(regStr);
//Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE); //忽略所有大小写
Matcher matcher = pattern.matcher(context);
while(matcher.find()){
System.out.println(matcher.group(0));
}
}
元字符-选择匹配符
public void test03(){
String context = "shao邵少天xiadiyi";
String regStr = "shao|邵|少";
//String regStr = "[A-Z]";
Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(context);
while(matcher.find()){
System.out.println(matcher.group(0));
}
}
元字符-限定符
java匹配默认是贪婪匹配,即尽可能的匹配多的部分,比如:a{3,4} aaaaaa12
会匹配出aaaa,而不是aaa和aaa
a+,1/多个a
a*,0/多个a
a1?,a1/a
元字符-定位符号
全字符串匹配!
@Test
public void test04(){
String context = "123abc";//可以匹配到
String content = "huanshunping spinghan";
//String context1 = "a123abc";//匹配不到,因为不以数字开头
String regStr = "^[0-9]+[a-z]*";
//表示匹配边界的han这里的边界是指:被匹配的字符串最后,
//也可以是空格的子字符串的后面
//String regStr = "han\\b";
Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(context);
while(matcher.find()){
System.out.println(matcher.group(0));
}
}
分组
基本分组
(pattern) :非命名捕获,捕获匹配的子字符串,编号为 0 的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺寻从 1 开始自动编号
(?pattren)命名捕获,将匹配的子字符串捕获到一个组名称或编号名称中,用于name的字符串不能包含任何标点符号,并且不能以数字开头,可以使用单引号替代尖括号,例如 (?'name’)
String str = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
sout(matcher.group(1));
sout(matcher.group("g1"));
//命名之后就会两种获取分组后子字符串的方法,没有命名只能通过顺序来获取
非捕获分组
这种分组,后面就只能通过matcher.group(0)方式来获取到值,不能通过matcher.group(1),matcher.group(2)…等等,因为不是捕获分组
public class RegExp01 {
public static void main(String[] args) {
String content = "hello韩顺平教育 jack韩顺平老师 韩顺平同学hello";
//String regStr = "韩顺平教育|韩顺平老师|韩顺平同学"
//String regStr = "韩顺平(?:教育|老师|同学)";
//只匹配韩顺平后面是 教育或者老师 的 韩顺平 的字符串
//String regStr = "韩顺平(?=教育|老师)";
//不匹配韩顺平后面是 教育或者老师 的 韩顺平 的字符串
String regStr = "韩顺平(?!教育|老师)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println(matcher.group(0));
}
}
}
在 限定符(* + ? {n} {n,} {n,m}) 后面加上一个问号(?)表示非贪婪匹配
应用
1.汉字
2.邮政编码:要求:是1-9开头的一个六位数,比如:123890
3.QQ号码:要求:是1-9开头的一个(5位数-10位数),比如:12389,1345678
4.手机号码:要求:必须以13,14,15,18开头的11位数,比如13588889999
5.URL:如:https://www.bilibili.com/video/BV1fh411y7R8from=search&seid=183160912083761326
String regStr = "^[\u0391-\uffe5]+$";
String regStr1 = "^[1-9]\\d{5}$";
String regStr2 = "^[1-9]\\d{4,9}$";
String regStr3 = "^1[3|4|5|8]\\d{9}$";
String content4 = "https://www.bilibili.com/video/BV1fh411y7R8?from=search&seid=183160912083761326";
String regStr4 = "^([https|http]://)(([\\w-]+\\.)+[\\w])+(\\/[\\w-?=&/%.#]*)?$";
常用类
Pattern类
Pattren 对象是一个正则表达式对象,Pattren类没有公共构造方法,要创建一个Pattern 对象,调用其公共静态方法,它返回一个Pattern 对象,该方法接收一个正则表达式作为它的一个参数,比如:Pattern r = Pattern.compile(pattern)
Pattern类的方法 matches,整体匹配,看content的内容,是否符合regStr的规则,有点类似 ^ $
String content = "hello abc hello 韩顺平教育";
String regStr = "hello";
String regStr = "hello.*";//true
boolean matches = Pattern.matches(regStr,content);
sout("整体匹配="+matches);//false
Matcher
PattrenSyntaxException
PatternSyctaxEcxeption是一个非强制异常类,它表示一个正则表达式模式中的语法错误
反向引用
给你一段文本,请你找出所有四个数字连在一起的子串,并且这四个数字要满足第一位和低四位相同,第二位和第三位相同,比如:1221,5775…
要解决前面的问题,我们需要了解正则表达式的几个概念:
分组:我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看做是一个子表达式/分组
捕获:把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组名,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推,组0表示的是整个正则式
反向引用:圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以式在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\分组号,外部反向引用¥分组号
去重案例
//老韩思路:先把点去掉
//String regStr = "\\.+"
//再把重复的 . 去掉
String content = "我...我要...学学学学...编程java!";
//String regStr1 = "(.)\\1{2,}";//我.我要.学.编程java!
String regStr = "\\.+";//我.我要.学.编程java!
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
content = matcher.replaceAll("");
System.out.println(content);
}
String regStr1 = "(.)\\1+";//我.我要.学.编程java!
Pattern pattern1 = Pattern.compile(regStr1);
Matcher matcher1 = pattern1.matcher(content);
while(matcher1.find()){
content = matcher1.replaceAll("$1");
System.out.println(content);
}