非贪婪匹配
非贪婪匹配的元字符是问号**?**
当此字符跟在任何其他限定符(*、+、?、{n}、{m}、{n,m})之后,匹配模式是 "非贪心的"。非贪心的意思就是每次匹配搜索到的尽可能短的字符串,可以是0个。
案例
对比贪婪匹配和非贪婪匹配
贪婪匹配
java
public static void main(String[] args) {
String content = "hello1010";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println(matcher.group(0));
}
}
输出结果:
java
1010
非贪婪匹配
java
public static void main(String[] args) {
String content = "hello1010";
Pattern pattern = Pattern.compile("\\d+?");
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println(matcher.group(0));
}
}
输出结果:
java
1
0
1
0
正则表达式应用实例
对字符串进行如下格式验证:
注意:格式验证不同于普通的匹配,格式匹配通常使用字符匹配符、定位符和限定符三种来进行匹配,尤其是限定符(定位符 ^ 、$),比如我们要判断 "123456"是不是三位数,如果我们使用如下的正则表达式:
java
\\d{3}
运行结果:
java
123
456
但其实是不匹配的,所以我们需要加定位符:
java
^\\d\\d{2}$
意思就是匹配以一位数字为开头,两位数字为结尾的字符串。
下面为了避免重复代码,我把模板放到这,只需要替换正则表达式的表达式即可。
java
Pattern pattern = Pattern.compile("");
Matcher matcher = pattern.matcher(content);
if (matcher.find()){
System.out.println("满足格式");
}
1、汉字
汉字的编码为 \u0391 到 \uffe5。
java
^[\u0391-\uffe5]+$
2、邮政编码
要求:是1~9开头的一个六位数
java
^[1-9]\\d{5}$
3、QQ号码
要求:是1-9开头的一个(5-10位数)
java
^[1-9]\\d{4,9}$
4、手机号码
必须 13,14,15,18 开头的11位数。
我们可以使用小括号和竖线符号表示逻辑或,也可以使用中括号进行范围表示。
java
^(13|14|15|18)\\d{9}$
//或者
^(1[3458])\\d{9}$
5、URL
URL 的匹配很重要,尤其是在网络爬虫中会经常用到。
java
https://blog.csdn.net/m0_64261982?spm=1000.2115.3001.5343
正则表达式:
java
^((http|https)://)?([\w-]+\.)+[\w-]+(\/[\w-?=&/%#.]*)?$
注意 :我们这里的正则表达式中的括号都是捕获分组 ,如果希望不捕获的话,可以在左半括号加一个问号?,这样就成了非捕获分组 ,非捕获分组的内容不会保存到Matcher类中的groups数组中去,而捕获分组的内容会保存到内存中,可以通过Matcher.group(int group)的方式从groups数组提取出来或者显示命名的分组可以通过自定义的组名提取出来(详细可以看我第二篇博客关于捕获分组的部分)。
java
System.out.println(matcher.group(0)); //https://blog.csdn.net/m0_64261982?spm=1000.2115.3001.5343
System.out.println(matcher.group(1)); //https://
System.out.println(matcher.group(2)); //https
System.out.println(matcher.group(3)); //csdn.
System.out.println(matcher.group(4)); ///m0_64261982?spm=1000.2115.3001.5343
其中:
|-------------------------------|---------------------------------------------|---------------------------------------------------------------------|
| ^((https)://)?
| https:// | 这里用了非贪婪匹配,网址可以省去协议 |
| ([\\w-]+\\.)+[\\w-]+
| blog.csdn.net
| 把带 '.' 的用([\\w-]+\\.)+ 来匹配,后缀 .com或者 .net 这些用 [\\w-]+ 来匹配 |
| (\\/[\\w-?=&/%#.]*)?$
| m0_64261982?spm=1000.2115.3001.5343
| 后面主要处理的就是一些特殊符号,看情况增加 |
注意: [?.*] 中括号里的点和问号只代表本身 没有特殊含义。
Pattern 类
之前我要做一些格式验证的话需要写很多代码,其实我们可以直接使用Pattern类中的一个matches方法,它可以对传入的正则表达式和字符串参数直接做一个整体匹配。
比如,验证QQ号:
java
System.out.println(Pattern.matches("^[1-9]\\d{4,9}$","3493247023"));
这样就可以极大地简洁代码,而不用去调用 Matcher 去一个个匹配。总之,Pattern.matches()适合做整体匹配,但不能做字符串中满足某一正则表达式的所有子串的匹配,所以看情况使用。
Matcher 类
这里介绍一些Matcher对象的其他方法。
我们以如下字符串为例:
java
小美喜欢小明,小明也喜欢小美。
start 和 end 方法
start 和 end 会输出匹配到的字符串的下标
java
String content = "小美喜欢小明,小明也喜欢小美。";
Pattern pattern = Pattern.compile("喜欢");
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println("=================");
System.out.println(matcher.group(0));
System.out.println(matcher.start());
System.out.println(matcher.end());
}
输出:
java
=================
喜欢
2
4
=================
喜欢
10
12
replaceAll 方法
把满足正则表达式的子串内容替换为参数的内容。
java
String content = "清华大学是中国著名的大学";
Pattern pattern = Pattern.compile("清华");
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
String res = matcher.replaceAll("山西农业");
System.out.println(res);
}
输出:
java
山西农业大学是中国著名的大学
反向引用
反向引用和分组、捕获是有关系的,下面是反向引用的概念:
圆括号的内容被捕获后,可以在这个括号后使用,从而写出一个比较实用的匹配模式,这个我们称之为反向引用,这种引用既可以是在正则表达式内部,用 \\分组号 ;也可以是在正则表达式外部,用**$分组号**。
案例1-AA
匹配两个连续的相同数字。
java
(\\d)\\1
案例2-AAAAA
匹配五个连续的相同数字。
java
(\\d)\\1{4}
案例3-ABBA
找出字符串中所有满足 ABBA 型的子串。
java
(\\d)(\\d)\\2\\1
java
String content = "12212121212222";
String regex = "(\\d)(\\d)\\2\\1";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println(matcher.group());
}
输出:
java
1221
2222
案例4
检索商品编号:形式如:12321-333999111 这样的号码,前面是一个五位数,然后是一个-,最后是一个AAABBBCCC型的9位数。
java
\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}
案例5-结巴去重
核心语句:(.)\\1+ 代表至少有两个重复字符的子串。
java
public static void main(String[] args) {
String content = "我...我要...学学学学...Java!";
// 1. 去掉所有的.
Pattern pattern = Pattern.compile("\\.");
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
// 2. 去掉重复的字
pattern = Pattern.compile("(.)\\1+");
matcher = pattern.matcher(content); //matcher 对象需要重新赋值
content = matcher.replaceAll("$1");
System.out.println(content);
}
简洁写法:
java
content = Pattern.compile("(.)\\1+").matcher(content).replaceAll("$1");
输出:
java
我要学Java!
String 类中的正则表达式
1、String.replaceAll(String regex,String replacement)
将content中满足正则表达式regex的子串替换为 replacement。
2、public boolean matches(String regex)
判断字符串是否满足正则表达式regex,相当于Pattern.matches(String regex,String content)。
3、public String[] split(String regex)
按照正则表达式regex分割字符串