常用正则表达式
一、正则表达式语法
1.元字符
- 字符匹配符
- 选择匹配符
- 限定符
- 定位符
- 分组组合和反向引用符
元字符(Metacjaracter)-转义号
\\
\\
符号 说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错。特殊:在Java的正则表达式中,两个
\\
代表其他语言中的一个\
需要用到转义符号的字符有
.
、*
、+
、(
、)
、&
、/
、\
、?
、[
、]
、^
、{
、}
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp01 {
public static void main(String[] args) {
String content = "a(.dd$.(%^(";
//匹配所有字符
// 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));
}
}
}
运行结果:
找到(
找到(
找到(
1.1字符匹配符
符号 | 符号含义 | 示例 | 解释 | 结果 |
---|---|---|---|---|
[] |
可接收的字符列表 | [efgh] | e、f、g、h中的任意1个字符 | e、h |
[^] |
不接收的字符列表 | [^abc] | 除a、b、c之外的任意1个字符 | d、h |
- |
连字符 | a-z | 任意单个小写字母 | a、b |
. |
匹配除\n以外的任意字符,如果只想匹配. 则需要用\\. |
a..b |
以a开头,b结尾,中间包括2个任意字符的长度为4的字符串 | addb、a#*b |
\\d |
匹配单个数字字符,相当于[0-9] |
\\d{3}(\\d)? |
包含3个或4个数字的字符串 | 123、7536 |
\\D |
匹配单个非数字字符,相当于[^0-9] |
\\D(\\d)* |
以单个非数字字符开头,后接任意个数字字符串 | a、R75 |
\\w |
匹配单个数字、大小写字母字符、下划线,相当于[0-9、a-z、A-Z、_] |
\\d{3}\\w{4} |
以3个数字字符开头的长度为7的数字字母字符串 | 456adFG、753Tfhd |
\\W |
匹配单个非数字、大小写字母字符,相当于[^0-9、a-z、A-Z、_] |
\\W+\\d{2} |
以至少1个非数字字母字符开头,2个数字字符结尾的字符串+代表1个或多个 | #52、$%^52 |
\\s |
匹配空白字符 | |||
\\S |
匹配非空白字符 |
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp02 {
public static void main(String[] args) {
String content = "ad44w8\n5.B6b5d";
//小写a-z
// String regStr = "[a-z]";
//大写A-Z
// String regStr = "[A-Z]";
//[^a-z]{2} 不在a-z之间的连续两个字符
// String regStr = "[^a-z]{2}";
//全部都匹配
String regStr = ".";
//方法一:(?i)不区分大小写
// String regStr = "(?i)wb";
Pattern pattern = Pattern.compile(regStr);
//方法二:这种方法也可以不区分大小写
// Pattern pattern = Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
}
[^a-z]{2} 不在a-z之间的连续两个字符结果
找到:44
找到:8
找到:5.
找到:B6
8后面那个是\n被换行了
1.2选择匹配符
在匹配某个字符串的时候是选择性的。即:既可以匹配这个,又可以匹配那个,这时需要用到选择匹配符号
|
符号 | 符号含义 | 示例 | 解释 |
---|---|---|---|
` | ` | 匹配` | `之前或之后的表达式 |
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp03 {
public static void main(String[] args) {
String content = "盖被子 dd 暖和阿斯顿aa想睡";
String regStr = "被子|暖和|睡";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
}
运行结果:
找到:被子
找到:暖和
找到:睡
1.3限定符
用于指定其前面的字符和组合项连续出现多少次
符号 | 符号含义 | 示例 | 解释 | 结果 |
---|---|---|---|---|
* |
指定符号重复0次或n次(无要求) | (abc)* | 仅包含任意abc的字符串 | abc、abcabc |
+ |
指定字符重复1次或n次(至少一次) | m+(abc)* | 以至少1个m开头,后接任意个abc的字符串 | m、mabc、mabcabc、mmabc |
? |
指定字符重复0次或1次(最多1次) | m+abc? | 以至少1个m开头,后接ab或abc的字符串,?接最近的 | mab、mabc、mmab |
{n} |
只能输入n个字符 | [abc] | 以abc中字母组成的任意长度为3的字符串 | abc、dbc、adc |
{n,} |
指定至少n个匹配 | [abcd] | 由abcd中字母组成的任意长度不小于3的字符串 | abc、ddddd |
{n,m} |
指定至少n个但不多于m个匹配 | [abcd] | 由abcd中字母组成的任意长度不小于3,并且不大于5的字符串 | abc、abcd、aaaaa |
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp04 {
public static void main(String[] args) {
String content = "asdmmabffm111111amabmabc";
// String regStr = "m+abc?";
//Java默认贪婪匹配,尽可能匹配多的
String regStr = "1{4,5}";
//结果只有5个1
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
}
1.4定位符
规定要匹配的字符串出现的位置,比如在字符串的开始还是在结束的位置
符号 | 符号含义 | 示例 | 解释 | 结果 |
---|---|---|---|---|
^ |
指定起始字符 | ^[0-9]+[a-z]* |
以至少1个数字开头,后接任意个小写字母的字符串 | 2、56f |
` | 符号 | 符号含义 | 示例 | 解释 |
----- | ---------------------- | ------------------ | ----------------------------------------------------------- | ------------------------------ |
^ |
指定起始字符 | ^[0-9]+[a-z]* |
以至少1个数字开头,后接任意个小写字母的字符串 | 2、56f |
| 指定结束字符 | ^[0-9]\\-[a-z]+$ |
以1个数字开头后接连字符- ,并以至少1个小写字母结尾的字符串 |
1-a、2-dd | ||
\\b |
匹配目标字符串的边界 | qy\\b |
这里的边界是指离空格最近的和离结束位置最近的 | qydsjdqy qyfffqy |
\\B |
匹配目标字符串的非边界 | qy\\b |
与\\b 相反,指开头第一次出现 |
qydsjdqy qyfffqy |
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp05 {
public static void main(String[] args) {
String content = "asdmmabffm111111a1";
//定位符只能找到一个返回
String regStr = "^[a-z]+[0-9]";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
}
//运行结果 找到:asdmmabffm1
1.5分组
1.5.1常用分组
常用分组构造形式 | 解释 |
---|---|
(pattern) |
非命名捕获。捕获匹配的子字符串。编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其它捕获结果则根据左括号的顺序从1开始自动编号。 |
(?<name>patter) |
命名捕获。将匹配的子字符串捕获到一个组名称或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?'name') 但是我尝试不能使用 |
非命名分组:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp06 {
public static void main(String[] args) {
String content = "qyxuexi dda5524 dadaqy";
String regStr = "(\\d\\d)(\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到=" + matcher.group(0));//5524
System.out.println("找到=" + matcher.group(1));//55
System.out.println("找到=" + matcher.group(2));//24
}
}
}
命名分组:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp06 {
public static void main(String[] args) {
String content = "qyxuexi dda5524 dadaqy";
String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到=" + matcher.group(0));//5524
System.out.println("找到=" + matcher.group("g1"));//55
System.out.println("找到=" + matcher.group("g2"));//24
}
}
}
1.5.2特别分组
特别分组构造形式 | 解释 |
---|---|
(?:patter) |
匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符` |
(?=pattern) |
它是一个非捕获匹配。例如,`Windows (?=95 |
(?!pattern) |
该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串。它是一个非捕获匹配。例如,`Windows (?!95 |
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp07 {
public static void main(String[] args) {
//说明非捕获的不能用group(1)去获取
String content = "hh阿典yyds 66阿典nb 99阿典xnlxixi";
//第一部分(?:patter)
// String regStr = "阿典yyds|阿典nb|阿典xnl";
//等价于非捕获分组
// String regStr = "阿典(?:yyds|nb|xnl)";
//第二部分(?=pattern)
//只找到阿典yyds与阿典nb中的阿典
// String regStr = "阿典(?=yyds|nb)";
//第三部分(?!=pattern)
//只找到不是阿典yyds与阿典nb中的阿典
String regStr = "阿典(?!yyds|nb)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:" + matcher.group(0));
}
}
}
2.非贪婪匹配
Java正则表达式默认的是贪婪匹配,如果想要进行非贪婪匹配就在需要的地方加一个?
案例:
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp01 {
public static void main(String[] args) {
String content = "456m";
// String regStr = "\\d+";//贪婪匹配 456
String regStr = "\\d+?";//非贪婪匹配 一个一个输出
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println("找到" + matcher.group(0));
}
}
}
二、正则表达式三个常用类
java.util.regex包主要包括以下三个类Pattern类、Matcher类和PatternSyntaxException
1.Pattern类
pattern对象是一个正则表达式对象。Pattern 类没有公共构造方法。要创建一个 Pattern对象,调用其公共静态方法,它返回一个 Pattern对象。该方法接受一个正则表达式作为它的第一个参数,比如:Patternr=Pattern.compile(pattern);
//整体匹配,就是全匹配上
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp10 {
public static void main(String[] args) {
String content = "https://space.bilibili.com/327811521?spm_id_from=333.1007.0.0";
//这里去掉了左右的定位符
String regStr = "((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.]*)?";
System.out.println(Pattern.matches(regStr,content));
}
}
2.Matcher 类
Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用 Pattern对象的matcher 方法来获得一个Matcher对象
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp11 {
public static void main(String[] args) {
String content = "hello ddd hello dsa$ hello";
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());
}
//matcher.replaceAll()用于替换
regStr = "hello";
pattern = Pattern.compile(regStr);
matcher = pattern.matcher(content);
//原来的文本并不会替换
/**
* 结果
* 你好 ddd 你好 dsa$ 你好
* hello ddd hello dsa$ hello
*/
String newContent = matcher.replaceAll("你好");
System.out.println(newContent);
System.out.println(content);
}
}
3.PatternSyntaxException
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
三、分组、捕获、反向引用
1.分组
我们可以用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式/一个分组。
2.捕获
把正则表达式中子表达式/分组匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。组0代表的是整个正则式
3.反向引用
圆括号的内容被捕获后,可以在这个括号后被使用,从而写出一个比较实用的匹配模式,这个我们称为反向引用,这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用
\\分组号
,外部反向引用$分组号
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp12 {
public static void main(String[] args) {
String content = "hel522511lo d1234111dd h55ell3o dsa$ hello";
//匹配连续相同的两个数字
//String regStr = "(\\d)\\1";
//String regStr = "(\\d)\\1{1}";
//String regStr = "(\\d)(\\d)";
//匹配连续三个相同的字符
//String regStr = "(\\d)\\1{2}";
//匹配个位与千位相同十位与百位相同的字符 如:1221
String regStr = "(\\d)(\\d)\\2\\1";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while(matcher.find()){
System.out.println("找到:"+matcher.group(0));
}
}
}
个人理解反向引用就是通过分组的组名去再次利用分组
四、正则表达式应用
1.简单应用
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp08 {
public static void main(String[] args) {
//汉字范围
// String content = "芊嵛要天天进步呀";
// String regStr = "^[\\u4E00-\\u9FA5]+$";
//邮政编码 0-9组成的6位数
// String content = "123456";
// String regStr = "^\\d{6}$";
//QQ号 1-9开头的
String content = "10006";
String regStr = "^[1-9][0-9]{4,10}$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}
2.判断url
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp09 {
public static void main(String[] args) {
String content = "https://space.bilibili.com/327811521?spm_id_from=333.1007.0.0";
/**
* 1.先用((http|https)://)确定url的开始部分 http:// | https://
* 2.再用([\w-]+\.)+[\w-]+确定space.bilibili.com
* 3.再用[\w-]+(\/[\w-?=&/%.]*)?确定/327811521?spm_id_from=333.1007.0.0
*
* 说明[]里面的东西都会是原样的
*/
String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.]*)?$";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if(matcher.find()){
System.out.println("满足格式");
}else{
System.out.println("不满足格式");
}
}
}
3.结巴去重
package com.qy.regexp;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @auther QY
*/
public class RegExp13 {
public static void main(String[] args) {
String content = "我....我要....学学学学...编程java!";
//1.去掉所有.(我我要学学学学编程java!)
Pattern pattern = Pattern.compile("\\.");
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
System.out.println(content);
//2.去掉重复的字
//使用反向引用$1来替换匹配到的内容
content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
System.out.println(content);
}
}
说明:
为什么一个
$1
就可以替换不同的字符呢,为什么不只是替换第一个字符,可能你有这样的疑问,解释:这还要看源码,通过源码我们可以得知分组的位置不是递增的而是一次一次被替换的,因此他始终会在1分组,开始
我
在1分组中,然后用我
替换了全部连续的我
,之后要替换我
进入第一个分组,重复上述操作等等
4.分割字符串
package com.qy.regexp;
/**
* @auther QY
*/
public class RegExp14 {
public static void main(String[] args) {
String content = "qy#dha-jd=你好=aj?d51~ddd";
String[] split = content.split("#|-|~|\\d+|=|\\?");
for (String i :split){
System.out.println(i);
}
}
}