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