正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1. 给定的字符串是否符合正则表达式的过滤逻辑,即是否匹配成功;
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。
不仅仅是在编程中使用,现在的很多编辑器搜索时都支持正则表达式匹配,所以很有必要学习其使用方法。接下来我们就开始来介绍一下正则表达式的基础使用。
1、基础
1.1 字符介绍
一般来说正则表达式就是以某种方式描述字符串,如以下几种最简单的方式:
- 可能有某个字符?:-? (可能有一个负号-)
- 有一个或多个之前的表达式+:\d+ (有一位或多位数字)
- 或操作|:-|A (有负号-或字符A)
注意:这里的\\表示“我想要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义”
所以这里表示一位数字用的是\\d。
常用的字符如下:
x 字符 x
\\ 反斜线字符
\0n 带有八进制值 0 的字符 n (0 <= n <= 7)
\0nn 带有八进制值 0 的字符 nn (0 <= n <= 7)
\0mnn 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh 带有十六进制值 0x 的字符 hh
\uhhhh 带有十六进制值 0x 的字符 hhhh
\t 制表符 ('\u0009')
\n 新行(换行)符 ('\u000A')
\r 回车符 ('\u000D')
\f 换页符 ('\u000C')
\a 报警 (bell) 符 ('\u0007')
\e 转义符 ('\u001B')
\cx 对应于 x 的控制符
常用的字符类如下:
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
[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](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
边界匹配符:
^ 行的开头
$ 行的结尾
...
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾
通过以上的一些基本知识,我们可以写出很多实用的正则表达式,如以下的这些:
- 匹配Email地址的正则表达式:w+([-+.]w+)@w+([-.]w+).w+([-.]w+)*
- 匹配由26个英文字母组成的字符串 ^[A-Za-z]+$
- 只能输入数字:“^[0-9]*$”
- 匹配中文字符 [u4e00-u9fa5](注:\u4e00-\u9fa5是所有汉字的unicode编码范围)
通过以上示例我们可以看见,运用正则表达式可以完成许多操作,而不用我们去用代码实现。当然还有更完善的匹配了模式,请继续往下看。
1.2 量词
量词描述了一个模式吸收输入文本的方式,有以下几种:
- 贪婪型:尽可能多的匹配,重复零次或更多。尝试匹配时,会选定尽可能多的内容,失败则回退一个字符,再次尝试回退的过程叫做回溯。相比下面两种贪婪量词对资源的消耗是最大的。
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
- 勉强型:匹配满足模式所需的最少字符数,即非贪婪型,重复一次或更多次
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
- 占有型:重复零次或一次
X?+ X,一次或一次也没有
X*+ X,零次或多次
X++ X,一次或多次
X{n}+ X,恰好 n 次
X{n,}+ X,至少 n 次
X{n,m}+ X,至少 n 次,但是不超过 m 次
以上的那些基本涵盖了常用的的各个方面,我们可以借用它们实现很多强大的功能了。很多语言都对正则表达式提供了很好的支持,我们这里用Java语言来介绍一下基本的使用。
2、Java正则表达式
在上一篇博文中我们讲文件操作时提到过Java类库对正则表示式的支持,在这一篇中,我们来详细的看看。
2.1 java.util.regex
java对正则表达式的支持在java.util.regex的包中,此包里含有两个类:
- Pattern: 正则表达式的编译表示形式。
- Matcher:通过解释 Pattern 对 字符序列执行匹配操作的引擎。
2.1.1 Pattern
指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。
典型的调用顺序是 :
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
更多关于Pattern类的详细方法可以参考下表:
返回值 | 方法 |
---|---|
static Pattern | compile(String regex) 将给定的正则表达式编译到模式中。 |
static Pattern | compile(String regex, int flags) 将给定的正则表达式编译到具有给定标志的模式中。 |
int | flags() 返回此模式的匹配标志。 |
Matcher | matcher(CharSequence input) 创建匹配给定输入与此模式的匹配器。 |
static boolean | matches(String regex, CharSequence input) 编译给定正则表达式并尝试将给定输入与其匹配。 |
String | pattern() 返回在其中编译过此模式的正则表达式。 |
static String | quote(String s) 返回指定 String 的字面值模式 String。 |
String[] | split(CharSequence input) 围绕此模式的匹配拆分给定输入序列。 |
String[] | split(CharSequence input, int limit) 围绕此模式的匹配拆分给定输入序列。 |
String | toString() 返回此模式的字符串表示形式。 |
注: compile(String regex, int flags)
中的flags代表不同的模式,我们可以改变此标志位来修改模式,如CASE_INSENSITIVE
:不区分大小写、COMMENTS
:允许空白和注释…。
2.1.2 Matcher
通过调用模式的 matcher 方法从模式创建匹配器(matcher)。创建匹配器后,可以使用它执行三种不同的匹配操作:
matches 方法尝试将整个输入序列与该模式匹配。
lookingAt 尝试将输入序列从头开始与该模式匹配。 (和matches不同的是不需要匹配整个区域)
find 方法扫描输入序列以查找与该模式匹配的下一个子序列。
每个方法都返回一个表示成功或失败的布尔值。通过查询匹配器的状态可以获取关于成功匹配的更多信息。
此类的方法较多,常用的方法如下:
返回值 | 方法 |
---|---|
boolean | matches():尝试将整个区域与模式匹配。 |
boolean | lookingAt(): 尝试将从区域开头开始的输入序列与该模式匹配。 |
boolean | find():尝试查找与该模式匹配的输入序列的下一个子序列。 |
boolean | find(int start):重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。 |
Pattern | pattern():返回由此匹配器解释的模式。 |
Matcher | reset():重置匹配器。 |
Matcher | reset(CharSequence input):重置此具有新输入序列的匹配器。 |
String | group():返回由以前匹配操作所匹配的输入子序列。 |
String | group(int group):返回在以前匹配操作期间由给定组捕获的输入子序列。 |
int | groupCount():返回此匹配器模式中的捕获组数。 |
2.2 Java正则表达式一个简单示例
以下代码演示了输入一个字符串数组,第一个字符串为输入的字符串,其余的为正则表达式。再分别将这些正则表达式用于输入的字符串上,得到匹配的结果。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestRE {
public static void main(String[] args) {
String[] input = { "abcabcabcdefabc", "abc+", "(abc)+", "(abc){2,}" };
if (input.length < 2) {
System.out.println("Usage:\njava TestRegularExpression "
+ "characterSequence regularExpression+");
}
System.out.println("Input: \"" + input[0] + "\"");
for (String str : input) {
System.out.println("Regular expression: \"" + str + "\"");
Pattern p = Pattern.compile(str);
Matcher m = p.matcher(input[0]);
while (m.find()) {
System.out.println("Match \"" + m.group() + "\" at positions "
+ m.start() + "-" + (m.end() - 1));
}
}
}
}
运行它,可以得到以下输出:
Input: "abcabcabcdefabc"
Regular expression: "abcabcabcdefabc"
Match "abcabcabcdefabc" at positions 0-14
Regular expression: "abc+"
Match "abc" at positions 0-2
Match "abc" at positions 3-5
Match "abc" at positions 6-8
Match "abc" at positions 12-14
Regular expression: "(abc)+"
Match "abcabcabc" at positions 0-8
Match "abc" at positions 12-14
Regular expression: "(abc){2,}"
Match "abcabcabc" at positions 0-8
可以看到,它起到了我们期望中的结果。 通过以上的方介绍两个类中的方法,可以实现很多的字符筛选和匹配,更详细的信息可以参考官方文档,如果以后有需要再完成剩下部分吧。^_^