Java正则表达式
正则表达式是对字符串执行模式匹配的技术.
正则表达式语法
元字符-转义符号\
\\符号
在Java的正则表达式中,两个\\
代表其它语言中的一个
需要用到转义符号的字符有以下:. * + ( ) $ / \ ? [ ] ^ { }
元字符-字符匹配符
符号 | 解释 | 示例 | 解释 |
---|---|---|---|
[ ] | 可接收的字符列表 | [abcde] | a,b,c,d,e中的任意1个字符 |
[^ ] | 不接收的字符列表 | [^abc] | 除a,b,c之外的任意1个字符,包括数字和特殊符号 |
- | 连字符 | [A-Z] | 任意单个大写字母 |
. | 匹配除\n以外的任何字符 | a..b | 以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 |
\\d | 匹配单个数字字符,相当于[0-9] | \\d{3}(\\d)? | 包含3个或4个数字的字符串 |
\\D | 匹配单个非数字字符,相当于[^0-9] | \\D(\\d)* | 以单个非数字字符开头,后接任意个数字字符串 |
\\w | 匹配任意英文字符,数字和下划线,相当于[0-9a-zA-Z_ ] | \\d{3}\\w{4} | 以3个数字字符开头的长度为7的数字字母_字符串 |
\\W | 匹配单个非数字,非大小写字母字符,非下划线,相当于[^0-9a-zA-Z_ ] | \\W+\\d{2} | 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 |
\\s | 匹配任何空白字符(空格,制表符等) | ||
\\S | 匹配任何非空白字符,和\\s 刚好相反 | ||
\\. | 匹配. 本身 |
[A-Z]
表示匹配A-Z中任意一个大写字符字符
[0-9]
表示匹配0-9中任意一个数字字符
[^a-z]
表示匹配不是a-z中的任意一个字符
[^A-Z]
表示匹配不是A-Z中的任意一个字符
[^0-9]
表示匹配不是0-9中的任意一个字符
不区分大小写
Java正则表达式默认是区分字母大小写的,如何实现不区分大小写呢?
(?i)abc表示abc都不区分大小写
a(?i)bc表示bc不区分大小写
a((?i)b)c表示只有b不区分大小写
Pattern pat=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE)
public class TestRegex {
public static void main(String[] args) {
String content= "a11c6abd9ABD";
//正则表达式
//String regStr="(?i)ABD"; //匹配abd字符串(不区分字母大小写)
String regStr="abd";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
//当创建Pattern对象时,指定Pattern.CASE_INSENSITIVE,表示匹配是不区分字母大小写的
Pattern pattern=Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}
找到1:abd
找到2:ABD
元字符-选择匹配符
符号 | 解释 | 示例 | 解释 |
---|---|---|---|
| | 匹配| 之前或之后的表达式 | ab|cd | 匹配ab或cd |
元字符-限定符
用于指定其前面的字符和组合项连续出现多少次
符号 | 含义 | 示例 | 说明 |
---|---|---|---|
* | 指定字符重复0此或多次 | (abc)* | 仅包含任意个abc的字符串 |
+ | 指定字符重复1次或多次(至少1次) | m+(abc)* | 以至少一个m开头,后接任意个abc的字符串 |
? | 指定字符重复0次或1次 | m+abc? | 以至少一个m开头,后接ab或abc |
{n} | 只能输入n个字符 | [abcd]{3} | 由abcd中字母组成的任意长度为3的字符串 |
{n,} | 指定至少n个匹配 | [abcd]{3,} | 由abcd中字母组成的任意长度不小于3的字符串 |
{n.m} | 指定至少n个但不多于m个匹配 | [abcd]{3,5} | 由abcd中字母组成的任意长度不小于3,不大于5的字符串 |
注意:Java匹配默认贪婪匹配,即尽可能匹配多的
public class TestRegex {
public static void main(String[] args) {
String content= "22222aaaaa49helloaaa";
//正则表达式
//Java匹配默认贪婪匹配,即尽可能匹配多的,如aaaaa就先匹配aaaa,剩下的一个a匹配不到
String regStr="a{2,4}";//表示匹配aa或aaa或aaaa
//String regStr="2+";//找到1:22222 贪婪匹配
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}
找到1:aaaa
找到2:aaa
(非)贪婪匹配
?
当此字符仅随任何其它限定符*+?{n}{n,}{n,m}
之后,匹配模式是非贪婪的
.非贪婪模式匹配搜索到的,尽可能短的字符串,而默认的贪心的
模式匹配搜索到的,尽可能长的字符串.例如:在字符串aaaa
中,"a+?"只匹配单个a,而"a+“匹配所有"a”
元字符-定位符
定位符,规定要匹配的字符串出现的位置.
符号 | 含义 | 示例 | 说明 |
---|---|---|---|
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少一个数字开头,后接任意个小写字母 |
$ | 指定结束字符 | ^[0-9]\\-[a-z]+$ | 以1个数字开头后接字符- ,并以至少1个小写字母结尾的字符串 |
\\b | 匹配目标字符串的边界 | hello\\b | 字符串边界指的是子串间有空格,或者是目标字符串的结束位置 |
\\B | 匹配目标字符串的非边界 | hello\\B | 和\\b 的含义相反 |
public class TestRegex {
public static void main(String[] args) {
String content= "hello java hellospark hellohadoop hello";
//正则表达式
//String regStr="hello\\b"; //匹配到第一个hello和最后一个hello
String regStr="hello\\B"; //匹配到第二个hello和第三个hello
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}
分组
常用分组
常用分组构造形式 | 说明 |
---|---|
(pattern) | 非命名捕获.捕获匹配的子字符串.编号为0的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号 |
(?<name>pattern) | 命名捕获.将匹配的子字符串捕获到一个组名称或编号名称中.用于name的字符串不能包含任何标点符号,并且不能以数字开头.可以使用单引号替代尖括号,例如(?'name') |
public class TestRegex {
public static void main(String[] args) {
String content= "hello java1134 hellospark2256 hellohadoop3378 hello";
//正则表达式
//String regStr="(\\d\\d)(\\d\\d)"; //非命名分组(只能用方法1捕获)
//命名分组:即可以给分组取名
String regStr="(?<group1>\\d\\d)(?<group2>\\d\\d)"; //匹配4个数字的字符串
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
System.out.println("================================");
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
System.out.println("第一个分组内容:"+matcher.group(1)); //方法1
System.out.println("第一个分组内容:"+matcher.group("group1")); //方法2
System.out.println("第二个分组内容:"+matcher.group(2));
System.out.println("第二个分组内容:"+matcher.group("group2"));
}
}
}
特别分组
常用分组构造形式 | 说明 |
---|---|
(?:pattern) | 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配.这对于用or 字符| 组合模式部件的情况很有用.例如:hello(?:spark|hadoop) 是比hellospark|hellohadoop 更经济的表达 |
(?=pattern) | 它是一个非捕获匹配.例如: 'Windows (?=95|98|200)' 匹配’Windows 200’中的Windows,但不匹配’Windows 3.1’中的Windows |
(?!pattern) | 该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串.它是一个非捕获匹配.例如: 'Windows (?!95|98|200)' 匹配’Windows 3.1’中的Windows,不匹配’Windows 200’中的Windows |
public class TestRegex {
public static void main(String[] args) {
String content= "hellojava java1134 hellospark2256 hellohadoop3378 hello";
//正则表达式
//命名分组:即可以给分组取名
//String regStr="hello(?:spark|hadoop)"; //匹配hellospark和hellohadoop
//String regStr="hello(?=java|spark)";
String regStr="hello(?!java|spark)";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}
matcher.find()完成的任务
不考虑分组
1.根据指定的规则,定位满足规则的子字符串
2.找到后,将 子字符串 的开始索引
记录到matcher对象的属性int [] groups;groups[0]
, 将该子字符串的结束索引+1
的值记录到groups[1]
3.同时记录oldLast
的值为 子字符串的结束索引+1
的值,即下次执行find时,就从这个位置开始匹配
group(int group)
方法根据groups[group*2],groups[group*2+1]
记录的位置,从content截取子字符串返回
matcher.group(0)
根据groups[0]和groups[1]记录的位置,从content开始截取子字符串返回
考虑分组
什么是分组?比如(\\d\\d)(\\d\\d)
,正则表达式中有()
表示分组,第一个()表示第一组,第二个()表示第二组…
1.根据指定的规则,定位满足规则的子字符串
2.找到后,将 子字符串 的开始索引
记录到matcher对象的属性int [] groups;groups[0]
, 将该子字符串的结束索引+1
的值记录到groups[1]
2.1将第一组()匹配到的字符串开始的索引记录到groups[2]
,结束的索引+1记录到groups[3]
2.2将第二组()匹配到的字符串开始的索引记录到groups[4]
,结束的索引+1记录到groups[5]
2.3如果有更多的分组,依次类推…
3.同时记录oldLast
的值为 子字符串的结束索引+1
的值,即下次执行find时,就从这个位置开始匹配
group(int group)
方法根据groups[group*2],groups[group*2+1]
记录的位置,从content截取子字符串返回
matcher.group(0)
根据groups[0]和groups[1]记录的位置,从content开始截取子字符串返回
总结:
如果正则表达式有分组(),取出匹配的字符串规则如下:
1)group(0)表示匹配到的子字符串
2)group(1)表示匹配到的子字符串中的第一组子串
3)group(2)表示匹配到的子字符串中的第二组子串
4)…依次类推(但是分组的数不能越界,即如果你有两个分组(),就不能出现group(3),否则报异常)
正则表达式常用类
Pattern类
pattern对象是一个正则表达式对象,Pattern类没有公共构造方法.要创建一个Pattern对象,调用其公共静态方法,它返回一个Pattern对象.该方法接受一个正则表达式作为它的第一个参数.比如:Pattern pattern=Pattern.compile(pattern);
matches()方法:用于整体匹配
public class TestRegex {
public static void main(String[] args) {
String content= "hellojava";
String regStr1="hello";
String regStr2="hellojava";
boolean matches1 = Pattern.matches(regStr1, content);
System.out.println("是否整体匹配成功:"+matches1); //false
boolean matches2 = Pattern.matches(regStr2, content);
System.out.println("是否整体匹配成功:"+matches2); //true
}
}
Matcher类
Matcher对象是对输入字符串进行解释和匹配的引擎.与Pattern类一样,Matcher也没有公共构造方法.需要调用Pattern对象的matcher方法来获得一个Matcher对象.
方法及说明 |
---|
public int start()返回以前匹配的索引 |
public int start(int group)返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引 |
public int end()返回最后匹配字符之后的偏移量 |
public int end(int group)返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量 |
public boolean lookingAt()尝试将从区域开头开始的输入序列与该模式匹配 |
public boolean find()尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true |
public boolean find(int start)重置此匹配器,然后尝试查找匹配该模式,从指定索引开始的输入序列的下一个子序列 |
public boolean matches()尝试将整个区域与模式匹配 |
public Matcher appendReplacement(StringBuffer sb,String replacement)实现非终端添加和替换步骤 |
public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换操作 |
public String replaceAll(String replacement)替换模式与给定替换字符串相匹配的输入序列的每个子序列 |
public String replaceFirst(String replacement)替换模式与给定替换字符串相匹配的输入序列的第一个子序列 |
public static String quoteReplacement(String s)返回指定字符串的字面替换字符串.这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作 |
public StringBuffer appendTail(StringBuffer sb)实现终端添加和替换步骤 |
public class TestRegex {
public static void main(String[] args) {
String content= "hellojava java1134 hellospark2256 hellohadoop3378 hello";
//正则表达式
String regStr="hello";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
String newContent1= matcher.replaceAll("hi");
System.out.println(newContent1);
String newContent2= matcher.replaceFirst("hi");
System.out.println(newContent2);
}
}
public class TestRegex {
public static void main(String[] args) {
String content= "hellojava java1134 hellospark2256 hellohadoop3378 hello";
//正则表达式
String regStr="hello";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("================================");
System.out.println("找到"+(++i)+":"+matcher.group(0));
System.out.println(matcher.start());
System.out.println(matcher.end());
System.out.println("找到:"+content.substring(matcher.start(),matcher.end()));
}
if(matcher.find(10)) {
System.out.println(matcher.start()); //19
System.out.println(matcher.group(0));
}
//整体匹配方法
System.out.println("整体匹配是否成功:"+matcher.matches()); //false
}
}
public class TestRegex {
public static void main(String[] args) {
String content= "hellojava java1134 hellospark2256 hellohadoop3378 helloscala";
//正则表达式
String regStr="hello";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
StringBuffer sb=new StringBuffer();
while (matcher.find()){
//将当前匹配的子字符串替换为指定字符串hi,并且将替换后的子字符串以及其之前到上次匹配子字符串之后的字符串段添加到sb里
matcher.appendReplacement(sb,"hi");
}
System.out.println(sb);//hijava java1134 hispark2256 hihadoop3378 hi
//将最后一次匹配工作后剩余的字符串添加到sb里
matcher.appendTail(sb);
System.out.println(sb);//hijava java1134 hispark2256 hihadoop3378 hiscala
}
}
PatternSyntaxException
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误
反向引用
1.分组:我们可以用()组成一个比较复杂的匹配模式,那么一个()我们可以看作是一个子表达式/一个分组
2.捕获:把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里
.从左往右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推.组0代表的是整个正则表达式.
3.反向引用:()的内容被捕获后,可以在这个括号后被使用
,从而写出一个比较实用的匹配模式,这个我们称为反向引用
,这种引用既可以是在正则表达式内部,也可以在正则表达式外部,内部反向引用\\分组号
,外部反向引用$分组号
public class TestRegex {
public static void main(String[] args) {
//要匹配个位与百位相同,十位与千位相同的数:4747 3737
String content= "hellojava4747 java11111 hellospark2256 hellohadoop3737 hello";
//正则表达式
String regStr="(\\d)(\\d)\\1\\2";
//String regStr="(\\d)\\1{4}"; //要匹配5个连续相同的数字
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("================================");
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}
结巴程序
把类似:“我…我要…学学学学…java编程!”
通过正则表达式修改成"我要学java编程!"
public class TestRegex {
public static void main(String[] args) {
String content= "我.....我要......学学学学.....java编程!";
//正则表达式
//1.去掉所有的.
String regStr="\\.";
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(regStr);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
content=matcher.replaceAll("");
//2.去掉重复的字
pattern=Pattern.compile("(.)\\1+");
matcher=pattern.matcher(content);
//通过反向引用$1来替换匹配到的内容
content=matcher.replaceAll("$1");
System.out.println(content);
}
}
String类中使用正则表达式
replaceAll
String类 public String replaceAll(String regex,String replacement)
public class TestRegex {
public static void main(String[] args) {
String content= "JDK1.3(Java Development Kit)称为Java开发包或Java开发工具,是一个编写Java的Applet小程序和应用程序的程序开发环境。" +
"JDK1.3是整个Java的核心,包括了Java运行环境(Java Runtime Environment),一些Java工具和Java的核心类库(Java API)。" +
"不论什么Java应用服务器实质都是内置了某个版本的JDK。主流的JDK是Sun公司发布的JDK," +
"除了Sun之外,还有很多公司和组织都开发了自己的JDK1.4,例如,IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK [17]。";
//使用正则表达式,将JDK1.3和JDK1.4替换成JDK
content=content.replaceAll("JDK1\\.(?:3|4)","JDK");
System.out.println(content);
}
}
matches
String类 public boolean matches(String regex)
整体匹配
public class TestRegex {
public static void main(String[] args) {
//验证一个手机号是不是以138 139开头的
String content="13864830864";
if(content.matches("1(38|39)\\d{8}")){
System.out.println("手机号是以138或139开头的");
}else {
System.out.println("手机号不是以138或139开头的");
}
}
}
public class TestRegex {
public static void main(String[] args) {
//要求验证是不是整数或者小数 0.32 -3.4 -5 +100 13.45
String content="-0.34";
String regStr="[+-]?([1-9]\\d*|0)(\\.\\d+)?";
if(content.matches(regStr)){
System.out.println("匹配成功 是整数或者小数");
}else {
System.out.println("匹配失败");
}
}
}
split
String类 public String[] split(String regex)
public class TestRegex {
public static void main(String[] args) {
String content="hellojava$hellohadoop@hellospark:helloscala-hellopython";
//分割字符串
String[] split = content.split("\\$|@|\\-|:");
for (String str : split) {
System.out.println(str);
}
}
}
案例
提取文章中所有的英文单词
public class TestRegex {
public static void main(String[] args) {
```java
String content= "JDK(Java Development Kit)称为Java开发包或Java开发工具,是一个编写Java的Applet小程序和应用程序的程序开发环境。" +
"JDK是整个Java的核心,包括了Java运行环境(Java Runtime Environment),一些Java工具和Java的核心类库(Java API)。" +
"不论什么Java应用服务器实质都是内置了某个版本的JDK。主流的JDK是Sun公司发布的JDK," +
"除了Sun之外,还有很多公司和组织都开发了自己的JDK,例如,IBM公司开发的JDK,BEA公司的Jrocket,还有GNU组织开发的JDK [17]。"
//提取文章中所有的英文单词
//String strReg="[a-zA-Z]+";
//提取文章中的所有数字
//String strReg="[0-9]+";
//提取文章中所有的英文单词和数字
String strReg="([0-9]+)|([a-zA-Z]+)"; //正则表达式
//先创建一个Pattern对象,模式对象(将给定的正则表达式编译成模式),可以理解为就是一个正则表达式对象
Pattern pattern=Pattern.compile(strReg);
//创建一个匹配器对象,matcher匹配器按照pattern(模式)到content文本中去匹配
Matcher matcher= pattern.matcher(content);
int i=0;
while (matcher.find()){ //尝试查找与模式匹配的输入序列的下一个子序列,找到则返回true
//匹配内容,文本,放到matcher.group(0)
System.out.println("找到"+(++i)+":"+matcher.group(0));
}
}
}