正则表达式在各种编程语言中几乎都有,其存在的最大意义是方面用户处理文本信息。比如:在一篇文章中查询其数字或者某写字段。
各自的语言在通过正则进行匹配的时候调用有所不同,但是其正则表达式本身区别不到。而本篇主要讲解分两部分Java正则调用底层是什么和正则表达式的格式
java中正则
文本的处理任何语言都无法避免的一种操作,这个一段先不讲解正则表达式的格式或者写法,而是了解java是如何调用正则。
老规矩先看调用代码。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class test {
public static void main(String[] args) {
String txt="汇编语言, 即第二代计算机语言,用一些容易理解和记忆的字母,"
+ "单词来代替一个特定的指令,比如:用“ADD”代表数字逻辑上的加减,"
+ "“ MOV”代表数据传递等等,通过这种方法,人们很容易去阅读已经完成的程序或者理解程"
+ "序正在执行的功能,对现有程序的bug修复以及运营维护都变得更加简单方便。但计"
+ "算机的硬件不认识字母符号,这时候就需要一个专门的程序把这些字符变成计算"
+ "机能够识别的二进制数。因为汇编语言只是将机器语言做了简单编译,所以并没有"
+ "根本上解决机器语言的特定性,所以汇编语言和机器自身的编程环境息息相关"
+ ",推广和移植很难,但是还是保持了机器语言优秀的执行效率,因为他的可阅读"
+ "性和简便性,汇编语言到现在依然是常用的编程语言之一。 汇编语言不像其他大多数的程序"
+ "设计语言一样被广泛用于程序设计。在今天的实际应用中,"
+ "它通常被应用在底层,硬件操作和高要求的程序优化的场合。"
+ "驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言。";
String rex="[A-Z,a-z]";// 表达式的意思就是查询字符串中还有的单个字母
Pattern pattern= Pattern.compile(rex);
Matcher matcher=pattern.matcher(txt);
while(matcher.find()) {
System.out.println(matcher.group(0));
}
}
}
// 输出
A
D
D
M
O
V
b
u
g
对于上面代码其实可以看出在java.util.regex下的两个主要的类Pattern,Matcher。简单的调用,根据上面的方法即可得知,但是有一个地方可能会有人注意到:matcher.group(0)。为什么我们取出的数据都是坐标为0.
通过图可以看出group数组中的下标二1的减去下标为0的总是等于汇编语言的长度:4
可以得出一个结论那就是group 这个数组,会存储查找到的数据的起始和结束坐标,然后没查找一个就会变一此。但是每次都是数组前两个变。
- 这个就有疑问了,明明是数组中的两个数,为什么group(0)?
public String group(int group) {
if (first < 0)
throw new IllegalStateException("No match found");
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
return null;
return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
}
源码可以得出,人家自己乘以2进行了一次运算了,所以
而getSubSequence 调用的的SubSequence方法,与字符串中的substring效果一样。
-
疑问2:如果group(0),直接定义长度为2的数组即可,干嘛还要创建要给大于2的数组呢?
其实这个有涉及到正则表达式中的捕获组的表达方式了。(先记住,后面聊)
这个可以看出来一点,那就是groups数组中给下标2,3代表都是是前面的小括号内容,下标4,5代表的是后面的小括号内容。而0,1代表是整体的内容。
现在再看group(int group) ,就明白group(1)和group(1)代表的内容了。
正则表达式
对于正则表达式有时候看着会觉得凌乱,其实不然,这个需要一种方式多用加强记忆,而主要记的就是其不同的符号代表的意思。
而根据不同的功能,元字符功能大致分:
- 限定符
- 选择匹配符
- 分组组合和反向引用符
- 特殊字符
- 字符匹配符
- 定位符
而这一篇将其放入java,那就是以Java作为基础进行演示,不过正则表达式规则,虽各个语言各有差异但有大体相同。
转义符
为什么要有转义符,因为有些特殊符号在正则表达式中有不同的涵义,但是有时候需要使用其本来字符代表的字符串意思。
比如 ( \ ),需要找找是否有这个符号,发现Java编译都编译不过去,有时候编译过去了,但是无法查询自己需要的字符串。所以需要转移符号写( \\ ),这样前面加一个反斜杠,其代表就是转移。
**注意:**而再java中的正则表达式转义符是 (\\) 等于其他语言的中的一个(\)
需要用到转义符号的字符:
. | * | + | ( |
---|---|---|---|
) | $ | / | \ |
? | [ | ] | ^ |
{ | } |
字符匹配符
符号 | 作用 | 示例 | 解释 |
---|---|---|---|
[ ] | 可接受的字符列表 | [abcd] | 选取abcd中的任意一个字符,不要看成一个连续abcd。 |
[ ^] | 不可接受的字符列表 | [^abcd] | 除去abcd之外的任意一个字符。 |
- | 连接符 | a-z | 任意一个小写字母 |
. | 匹配除了\n以外任何一个字符 | a…b | 以a开头,以b结尾,中间有两个除\n以外的字符(因为前面写了两个 . )a±b,abgb等 |
\\d | 匹配单个数字的字符,相当于[0-9] | \\d | 可以得到任何单个数字,比如0,1,9等单个数字,不过一般会搭配限定符一起用 |
\\D | 匹配单个非数字字符,相当于[^0-9] | \\D | 可以得到任何除了数字的字符,比如:A,a,+,%等。不过一般也会跟着限定符一起用。 |
\w | 匹配单个数字,大小写字符,相当于[0-9a-zA-Z] | \w | 可以得到数字,大小写字符的,比如:A,a,1,等。不过一般也会跟着限定符一起用。 |
\W | 匹配单个非数字,大小写字符,相当于[^0-9a-zA-Z] | \W | 可以得到除了数字,大小写字符的,比如:%,+,-,等。不过一般也会跟着限定符一起用。 |
String str="a2b+3cdABC#我";
String rex="这个根据要求在现在写";
Pattern pattern= Pattern.compile(rex);
Matcher matcher=pattern.matcher(txt);
while(matcher.find()) {
System.out.println(matcher.group(0));
}
# 匹配字符串中小写字符。
rex="[a-z]";
因为可以看出其小写只有abcd 也可以写:rex="[abcd]";不过一般除非定义匹配这四个字符,不然一般执行写a-z
输出:
a
b
c
d
# 匹配字符串中的数字
rex="[0-9]";
或者: rex="\\d";
输出:
2
3
# 匹配字符串中的非数字,大小写字母的字符
rex="{\\W}";
或者: rex="[^0-9A-Za-z]";
输出:
+
#
我
限定符
用于指定前面的字符和组合项目连续出现的次数。
符号 | 含义 | 示例 | 说明 |
---|---|---|---|
* | 指定字符重复0次或n次 | hg(abc)* | 会匹配hg,hgabc 或者hg ,abcabc等字符串, |
+ | 指定字符重复1次或n次(要求必须出现一次) | hg(abc)+ | 会匹配hgabc 或者abcabc等字符串, |
? | 指定字符重复出现0次或者1次 | hg(abc)? | 会匹配hgabc 或者hg 这两种字符串 |
{ n } | 指定字符串重复出现n次 | hg(abc){2} | 会匹配bgabcabc 这个样子的字符串 |
{n,} | 指定至少n个匹配 | [abc]{2,} | 会匹配aa,aba,aaaa,ac,ca,等字符串能长度低于2 |
{n,m} | 指定至少n个但是不多与m个匹配 | [abc]{2,3} | 会匹配 ac ,aac,ccc等字符串不能长度超过3,低于2 |
| | 选择匹配符 | hg|abc | 会匹配hg或者abc的字符串 |
String str="abc45abcbc++a";
String rex="这个根据要求在现在写";
Pattern pattern= Pattern.compile(rex);
Matcher matcher=pattern.matcher(txt);
while(matcher.find()) {
System.out.println(matcher.group(0));
}
## 匹配a如果a字母后面有bc的话无论重复几次bc也需要匹配
rex="a(bc)*";
输出:
abc
abcbc
a
##匹配bc的字符前面有a的字符,无论出现多少次bc
rex="a(bc)+";
输出
abc
abcbc
## 匹配a以及a后面有一次bc的字符串
rex="a(bc)?";或者 rex="a|abc";
输出:
abc
abc
a
## 匹配abcbc文件
rex="a(bc){2}"; 或者 rex="abcbc";
输出:
abcbc
## 匹配字母长度连续大于2,小于4的字符串
rex=[a-z]{2,4};
输出:
abc
abcb
分组
这个前面用到了多次,那就是一对()
格式 | 说明 |
---|---|
(pattern) | 非命名捕获,捕获匹配的子字符串。编号为零的第一个捕获的由整个正则表达式模式匹配的文本,其他的捕获结果则根据左右括号的顺序从1开始自动编号。(具体理解,可以看java正则的截图) |
(?<name> pattern) | 命名捕获,捕获匹配的子字符串,以及给其一个组名或编号的名称中。用与name的字符串不能包含任何标点符号,并且不能以数字开头,额可以使用单引号代替尖括号,例如(?‘name’) |
(?:pattern) | 特殊的分组,匹配pattern但不捕获该匹配的子表达式,即他是一个非捕获的匹配,不存储供以后使用的匹配。这个对于用“or”字符(|)组合模式部件的情况很有用sb(?:ni|ta)比表达式 sbni|sbta一样,如果使用group(1) 会报错没有这个值。 如果写成sb(ni|ta),那么就可以用group(1)可以取数据了。 |
(?=pattern) | 特殊分组,是一个非捕获的匹配。比如sb(?=ni) 如果sb后面是ni那么就会取出sb,如果sb后面是除了ni以外比如ta就不会取出。注意:只会匹配得到sb而不是sbni,同意group(1)也是没有数据的。 |
(?!pattern) | 特殊分组,是一个非捕获的匹配,和(?=pattern)相反。比如sb(?!ni) 如果sb后面是ni那么就不会会取出sb,如果sb后面是除了ni以外比如ta就会取出。注意:只会匹配得到sb而不是sbta,同意group(1)也是没有数据的。 |
String txt="汇编语言, 即第二代计算机语言,用一些容易理解和记忆的字母,"
+ "单词来代替一个特定的指令,比如:用“ABCDEFGHIJK”代表数字逻辑上的加减,"
+ "“ MOV”代表数据传递等等,通过这种方法,人们很容易去阅读已经完成的程序或者理解程"
+ "序正在执行的功能,对现有程序的bug修复以及运营维护都变得更加简单方便。但计"
+ "算机的硬件不认识字母符号,这时候就需要一个专门的程序把这些字符变成计算"
+ "机能够识别的二进制数。因为汇编语言只是将机器语言做了简单编译,所以并没有"
+ "根本上解决机器语言的特定性,所以汇编语言和机器自身的编程环境息息相关"
+ ",推广和移植很难,但是还是保持了机器语言优秀的执行效率,因为他的可阅读"
+ "性和简便性,汇编语言到现在依然是常用的编程语言之一。 汇编语言不像其他大多数的程序"
+ "设计语言一样被广泛用于程序设计。在今天的实际应用中,"
+ "它通常被应用在底层,硬件操作和高要求的程序优化的场合。"
+ "驱动程序、嵌入式操作系统和实时运行程序都需要汇编语言。";
String rex="(?<name1>汇编)(?<name2>语言)";
Pattern pattern= Pattern.compile(rex);
Matcher matcher=pattern.matcher(txt);
while(matcher.find()) {
System.out.println("=====全部"+matcher.group(0));
System.out.println("=====0"+matcher.group(1));
System.out.println("=====0"+matcher.group("name1"));
System.out.println("=====1"+matcher.group(2));
System.out.println("=====1"+matcher.group("name2"));
}
//输出
=====全部:汇编语言
=====0:汇编
=====0:汇编
=====1:语言
=====1:语言
......
=====全部:汇编语言
=====0:汇编
=====0:汇编
=====1:语言
=====1:语言
定位符
定位符规定要匹配的字符串出现的位置,比如在字符串的开始还是结束,这个也是很常用的功能,比如匹配邮箱或者url地址等。
符号 | 含义 | 示例 | 说明 |
---|---|---|---|
^ | 指定起始字符(和[^]代表的意思不一样,不要记错) | ^[1,3]+[a-z]* | 至少1个数字开头,后面有任意小写字母。例如:13adf,2fgf等 |
$ | 指定结束字符 | ^[1,3]+\\*$ | 至少1个数字开头,但是最后一位必须是*结尾 |
\\b | 匹配目标字符串的边界 | sb\\b | 字符串的边界指的是子串间有空格,或者是目标字符串的结束位置,比如:sbdfsb sbdfdsb |
\\B | 与\\b刚刚相反 | sb\\B | sbdfsb sbdfdsb |
补充
正则表达式在匹配的时候有两个模式:贪婪匹配和非贪婪匹配。
-
贪婪匹配:那就是在匹配的时候,尽可能的长的数据。比如使用:{n,m},+,?,*
在使用中,尽可能匹配最长的字符串。
txt="123WER13445+df13"; String rex="\\d{2,5}";// 匹配长度为2到5个数字的字符串 Pattern pattern= Pattern.compile(rex); Matcher matcher=pattern.matcher(txt); while(matcher.find()) { System.out.println("=====全部:"+matcher.group(0)); } //输出 =====全部:123 =====全部:13445 =====全部:13
可以看出其匹配。尽可能的长。
-
非贪婪匹配:这种匹配的时候如果以满足匹配,就不会在继续让其变的更长。比如在{n,m},+,*后面添加一个?,看下面代码演示:
txt="123WER13445+df13";
String rex="\\d{2,5}?";// 匹配长度为2到5个数字的字符串
Pattern pattern= Pattern.compile(rex);
Matcher matcher=pattern.matcher(txt);
while(matcher.find()) {
System.out.println("=====全部:"+matcher.group(0));
}
//输出
=====全部:12
=====全部:13
=====全部:13