正则表达式(二)
三、分组引用
3.1、什么是分组
分组指将匹配的内容,使用( )划分成多个组块,分好的组可用于提取、反向引用以及替换操作。
例如在 Java 中
public static void main(String[] args) {
Pattern pattern=Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher("小丽生日是2011-11-23");
if (matcher.find()) {
String month = matcher.group(2);// 获取第2组中的月份
System.out.println("月份是:"+month);
}
}
// 输出如下结果:
"月份是:11"
3.2、反向引用
在表达式中引用之前的分组,即反向引用
例如
<h1>一级标题</h1>
<h2>二级标题</h2>
<h2>三级标题</h3>
<h4>四级标题</h4>
<h5>五级标题</h5>
<h6>六级标题</h6>
html中共有6级标题,标签是h[1-6],得出匹配正则<h[1-6]>.*?<\/h[1-6]>,正常情况下它能匹配所有标题,问题在于文中的标题三是错误的,<h2>三级标题</h3>,它是h2开头,结尾确是h3
使用反向引用可以更轻松解决这个问题:<(h[1-6])>.*?<\/\1>
步骤拆解如下:
<(h[1-6])>
匹配开始标签,并把标签名加入分组1.*?
标签中间可以是任意内容。<\/\1>
匹配结束标签,标签内容通过\1
引用分组1(意思是与分组1的内容一致)
反向引用指通过\组号
引用之前的分组,可以把分组理解成一个变量,在通过变量名(组号)引用。它不能引用之后的内容,固作称作反向引用,比如这样正则是错误的:<\1>.*?<\/(h[1-6])>
3.3、引用替换
我们经常使正则然后进行替换操作,比如匹配文中所有空行,然后替换成空(删除它),又或者是找出错误的单词,替换成正确的。其实正则有更为强大的替换能力,比如把普通文中所有http链接,一键替换成<a >标签,更厉害一点还可以把文本替换成 insert sql 语句。
请找出下文中所有日期,并统一替换成yyyy-MM-dd
格式:
1994-05-27
1972/08/09
1983.05.22
1960/02/19
1986/12/15
1978.01.03
1978/02/21
1964/09/20
1978/08/13
- 写出匹配日期的正则:
\d{4}[-.\/]\d{2}[-.\/]\d{2}
- 对日期年、月、日进行分组:
(\d{4})[-.\/](\d{2})[-.\/](\d{2})
- 在替换字符中引用分组:
$1-$2-$3
替换操作指将正则匹配到的内容,替换成指定字符串,该字符串可通过$组号引用组进行拼装。通过$0可以引用整个匹配的内容。比如:日期“1960/02/19”被匹配之后 $0表示整个日期,$1、$2、$3 分别表示年月日。请注意反向引用与替换引用的语法区别,前者是使用\组号,而替换使用$组号。
注意:$0
在 Python与Javascript中不支持,使用$&
代替
//Java
String s = "1978/08/13".replaceAll("(\\d{4})[-.\\/](\\d{2})[-.\\/](\\d{2})",
"$1-$2-$3");
System.out.println(s);
// 输出结果
1978-08-13
大小写转换
在Idea、VS Code、Sublime、Notepad++等工具进行替换操作时,还可以使用下表中操作符进行大小写转换:
操作符 | 描述 |
---|---|
\u 单个转大写 | 转换一下个字符为大写 |
\U 全部转大写 | 转换\U后所有字符转大写 |
\U…\E 区间转大写 | \U与\E区间的内容转大写 |
\l 单个转小写 | 转换一下个字符为小写 |
\L 全部转小写 | 转换\L后所有字符转小写 |
\L…\E 区间转小写 | \L与\U区间的内容转小写 |
具体使用方法是:在替换字符串中加入转换操作符。举例把单词首字母转成大写:
- 编写匹配正则:
\w+
- 首字母转大写并替换:
\u$0
3.4、分组的其它应用
3.4.1、(?<名称> )
命名分组
默认情况下通过组号来取值,此外也可以自定义命名组,语法是(?<名称> )
,然后在程序中就可以通过<>
中的名称
来取值。如:<(?<title>h[1-6])>.*?<\/\1>
该表达式就命名了一个title的组,在js的结果中就可通过title属性取值。
注意:这种命名组只能用于在程序中提取操作,不能进行反向引用,也不能用在替换操作中。上例在替换中如果使用 $title
或在反向引用中使用 \title
都是无效的。只能通过组号\1
进行引用。这也说明命名组后,组号一样有效。也正因为这种局限性所以命名组使用的很少。
3.4.2、(?: )
移除分组
()
即用于子表达式,同时也是一个分组。如果只想用作子表达式,而不想用于分组就可以使用(?: )
从分组列表中移除。比如(?:\d{4})-(\d{2})-(\d{2})
该表达式只存在两个组,月$1
和日$2
。
3.4.3、( ( ) )
嵌套分组
在嵌套分组中组号是如何命名的呢?比如:生日((\d{4})-(\d{2})(\d{2}))
其组号的命名顺序是以开括号出现顺序为准。
3.4.4、()+
分组使用量词
同一个分组如果使用了量词,该分组会代表多个值,这时通过$组号
去提取值的时候会得到该组最后匹配的值。如(\d)+
匹配12345,通过$1
将得到5
示例
正则为(.+?) / (.+?) / (\d{2}) KG / (\d{4}).(\d{2}).(\d{2})
替换为insert into user (name,city,weight,birthday) values('$1','$2',$3,'$4-$5-$6');
本作品采用《CC 协议》,转载必须注明作者和本文链接