正则表达式是什么?
正则表达式是一种强大而灵活的文本处理工具。初学正则表达式时,其语法是一个难点,但它确实是一种简洁、动态的语言。正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配、选择、编辑以及验证。一般来说,正则表达式就是以某种方式来描述字符串。
日常例子
在文本中查找“halu126”,我们通常会在查找框中输入“halu126”,这就是一个最简单的正则表达式的例子,使用精确的匹配这样的字符串,如果我 们即想在文本中找到“halu126”,又想找到“Halu126”,却不想找到“aaaHalu126bbbb”中的“Halu126”,该怎么办?
在linux中我们想查想列出所有的Java源文件,通常会在终端中输入:ls -all *.java,其中“*”是叫做通配符,而正则表达式比通配符更牛,它能更精确的描述你的需求。
正则表达式的构造摘要
构造 | 匹配 |
---|---|
字符 |
|
X |
字符X |
\\ | 反斜线字符 |
|
制表符 |
|
换行符 |
|
回车符 |
字符类 |
|
[abc] |
a、b 或 c(简单类) |
[^abc] |
任何字符,除了 a、b 或 c(否定) |
[a-zA-Z] |
a 到 z 或 A 到 Z,两头的字母包括在内(范围) |
[a-d[m-p]] |
a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[def]] |
d、e 或 f(交集) |
[a-z&&[^bc]] |
a 到 z,除了 b 和 c:[ad-z](减去) |
预定义字符类 |
|
. |
任何字符 |
d |
数字:[0-9] |
D |
非数字:[^0-9] |
s |
空白字符:[
x0Bf
] |
S |
非空白字符:[^s] |
w |
单词字符:[a-zA-Z_0-9] |
W |
非单词字符:[^w] |
边界匹配器 |
|
^ |
行的开头 |
$ |
行的结尾 |
|
单词边界 |
B |
非(单词边界) |
量词 |
|
X? |
X,一次或一次也没有 |
X* |
X,零次或多次 |
X+ |
X,一次或多次 |
X{n} | X,恰好n次 |
X{n,} | X,至少n次 |
X{n,m} | X,至少n次,但是不超过m次 |
Logical运算符 |
|
XY |
X后跟Y |
X|Y |
X或者Y |
(X) |
X,作为捕获组 |
组和捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式中((A)(B(C)))中,存在四个这样的组
1 | ((A)(B(C))) |
2 |
(A) |
3 |
(B(C)) |
4 |
(C) |
Java语言中正则表达式的不同处
在其他语言中,“ \”表示“我想在正则表达式中插入一个普通的(字面上的)反斜线,请不要给它任何特殊的意义。”在Java语言中,“\”表示“我要插入一个正则表达 式的反斜线,所以其后的字符具有特殊的意思。”例如:“\d”表示Java语言中正则表达式的一位数字。“\\”表示一个普通的反斜线。不过换行和 制表符之类的东西只需要使用单反斜线:“ ”。
量词的类型:
量词:描述了一个模式吸收(匹配)输入文本的方式,也叫做重复限定符。
贪婪型:量词总是贪婪的,除非有其他的选项被设定。贪婪表达式会为所有可能的模式发现尽可能多的匹配。
勉强型:用问号指定,这个量词匹配满足模式所需的最少字符数。因此也称作懒惰的、最少匹配的、非贪婪的、或不贪婪的。
占有型:Java中独有的。其他语言没有。当正则表达式被应用于字符序列时,它会产生相当多的状态,以便在匹配失败时可以回溯。而“占有的”量词并不保存这些中间状态,因此他们可以防止回溯。他们常常用于防止正则表达式失控,因此可以使正则表达式执行起来更有效。
Greedy数量词 | Reluctant数量词 | Possessive数量词 |
---|---|---|
X? |
X?? |
X?+ |
X* |
X*? |
X*+ |
X+ |
X+? |
X++ |
X{n} |
X{n}? |
X{n}+ |
X{n,} |
X{n,}? |
X{n,}+ |
X{n,m} |
X{n,m}? |
X{n,m}+ |
量词作用的表达式通常必须要使用圆括号括起来。
String类中使用正则表达式的方法
matches(String regex)
split(String regex)
split(String regex, int limit)
replaceFirst(String regex, String replacement)
repalceAll(String regex, String replacement)
Java语言中表示正则表达式的类
在Java语言中与正则表达式相关的类都放在java.util.regex包。
- *Pattern类:*pattern对象是一个正则表达式的编译表示。Pattern类没有公共构造方法。要创建一个Pattern对象,你必须首先调用其公共静态编译方法,它返回一个Pattern对象。该方法接受一个正则表达式作为它的第一个参数。
- *Matcher类:*Matcher对象是对输入字符串进行解释和匹配操作的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的matcher方法来获得一个Matcher对象。
- *PatternSyntaxException:*PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建Matcher对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
因此,典型的调用顺序是
1 Pattern pattern = Pattern.compile("a*b"); 2 Matcher matcher= pattern("aaaaaaab"); 3 matcher.XXX();
一个简单的代码如下:
1 public class TestRegularExpression { 2 public static void main(String[] args) { 3 if(args.length < 2) { 4 print("Usage: java TestRegularExpression " + 5 "characterSequence regularExpression+"); 6 System.exit(0); 7 } 8 print("Input: "" + args[0] + """); 9 for(String arg : args) { 10 print("Regular expression: "" + arg + """); 11 Pattern p = Pattern.compile(arg); 12 Matcher m = p.matcher(args[0]); 13 while(m.find()) { 14 print("Match "" + m.group() + "" at positions " + 15 m.start() + "-" + (m.end() - 1)); 16 } 17 } 18 } 19 }
Pattern和Matcher类中常用的方法
1 //使用Pattern类的静态方法compile来编译正则表达式,它会根据正则表达式regex生成一个Pattern对象。 2 Pattern pattern = Pattern.compile(String regex) 3 //检查regex是否匹配整个CharSequence类型的input参数 4 Pattern.matches(String regex, CharSequence input) 5 //从匹配了regex的地方分割输入字符序列input 6 pattern.split(CharSequence input) 7 //同String.split() 8 pattern.split(CharSequence input, int limit) 9 //根据模板pattern生成input的匹配器matcher 10 Matcher matcher = pattern.matcher(CharSequence input); 11 //从字符序列的开始位置(0位字符)迭代的向前遍历字符序列,找到匹配模式的部分 12 matcher.find() 13 //从字符序列的第start位字符开始(以第start位字符作为搜索的起点)迭代的向前遍历字符序列,找到匹配模式的部分 14 matcher.find(int start) 15 //判断整个输入字符序列是否匹配正则表达式模式 16 matcher.matches() 17 //判断该字符序列(不必是整个字符序列)的开始部分是否能够匹配模式 18 matcher.lookingAt() 19 //该匹配器的模式中的分组数目 20 matcher.groupCount() 21 //返回前一次匹配操作(例如find())的第0组(即整个匹配) 22 matcher.group() 23 //返回在前一次操作期间指定的组号,如果没有指定的组,返回null 24 matcher.group(int group) 25 // 26 matcher.start() 27 //返回前一次匹配操作中寻找到的组的起始索引 28 matcher.start(int group) 29 matcher.end() 30 //返回前一次匹配操作中寻找到的组的最后一个字符索引加一的值 31 matcher.end(int group) 32 //将matcher对象重新设置到当前字符序列的起始位置 33 matcher.reset() 34 将现有的matcher对象应用到一个新的字符序列 35 matcher.reset(CharSequence input)
使用正则表达式时要注意的事儿
要匹配一种情况,我们可以写出多个可行的正则表达式,当然了,我们的目的并不是编写最难理解的正则表达式,而是尽量编写能够完成任务的、最简单以及最必要的正则表达式。
参考
- Java编程思想
- JDK API文档
- 正则表达式30分钟入门教程
- RUNOOB中关于正则表达式的介绍