Java正则表达式学习(一)
1.什么是正则表达式:
正则表达式(regular expressions) 是一种描述字符串集的方法,它是以字符串集中各种字符串的公有特征为依据的。
正则表达式可以用于搜索、编辑或者操作文本和数据。许多程序设计语言都支持利用正则表达式进行字符串操作。
正则表达式这个概念最初是由Unix中工具软件(例如sed和grep)普及开来的。正则表达式通常缩写成"regex"。
2.java.util.regex包是如何描述正则表达式的?
java.util.regex 包主要由三个类所组成:Parten、Matcher和PatternSyntaxException。
Pattern 对象表示一个已编译的正则表达式。Patter类没有提供公有的构造方法。要构造一个模型,首先必须调用公共的静态compile方法,它将返回一个Pattern对象。这个方法接受正则表达式作为第一个参数。
Matcher 是一个靠着输入的字符串来解析这个模式和完成匹配操作的对象。与Pattern相似,Matcher也没有定义公共的构造方法,需要通过调用Pattern对象的matcher方法来获得一个Matcher对象。
PatternSyntaxException 对象是一个未检查异常,指示了正则表达式中的一个语法错误。
测试正则表达式工具,java版
在后面的实例中,可通过该工具来验证
package com.fortune.test;
import java.io.Console;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created with IntelliJ IDEA.
* User: Alan
* Date: 12-5-28
* Time: 下午1:46
*/
public class RegexTestHarness {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.printf("%nEnter your regex: ");
Pattern pattern = Pattern.compile(scanner.nextLine());
System.out.printf("Enter input string to search: ");
Matcher matcher = pattern.matcher(scanner.nextLine());
boolean found = false;
while (matcher.find()) {
System.out.printf(
"I found the text \"%s\" starting at index %d and ending at index %d.%n",
matcher.group(), matcher.start(), matcher.end()
);
found = true;
}
if (!found) {
System.out.printf("No match found.%n");
}
}
}
}
3.字符串验证
在大多数的情况下,API所支持模式匹配的基本形式是匹配字符串,如果正则表达式是foo,输入的字符串也是foo,这个匹配将会是成功的。因为这两个字符串是相同的。试着用测试工具来测试一下:
Enter your regex: foo
Enter input string to search: foo
I found the text "foo" starting at index 0 and ending at index 3.
结果确实是成功的。注意当输入的字符串是3个字符长度的时候,开始的索引时0,结束的索引是3。这个是约定俗成的,范围包括开始的索引,不包括结束的索引,如下图所示:
图1 字符串"foo"的单元格编号和索引值
字符串中每一个字符位于其自身的单元格(cell)中,在每一单元格之间有索引指示位。字符串"foo"始于索引0处,止于索引3处,即使是这些字符它们自己仅占据了0、1和2号单元格。
就子序列匹配而言,你会注意到一些重叠,下一次匹配开始索引与前一次匹配的结果索引是相同的:
Enter your regex: foo
Enter input string to search: foofoofoo
I found the text "foo" starting at index 0 and ending at index 3.
I found the text "foo" starting at index 3 and ending at index 6.
I found the text "foo" starting at index 6 and ending at index 9.
4.元字符验证
API也支持许多可以影响模式匹配的特殊字符。把正则表达式改成 cat. , 并输入字符串"cats",输出结果是下所示:
Enter your regex: cat.
Enter input string to search: cats
I found the text "cats" starting at index 0 and ending at index 4.
虽然在输入的字符串中没有点(.),但这个匹配仍然是成功的。这是由于点(.)是一个元字符(metacharacters)(被这个匹配翻译成了具有特殊意义的字符了)。这个例子为什么能匹配在于, 元字符.指的是"任意字符".
API所支持的元字符有:([{\^-$|}])?*+.
注意:在学习过更多的如何构建正则表达式后,你会碰见这些情况:上面的这些特殊字符不应该被处理为元字符。然而也能够使用这一清单来检查一个特殊的字符是否会被认为是元字符。例如,字符!、@和#绝不会有特殊意义。
有两种方式可以强制将元字符处理成为普通字符:
1.在元字符前加上反斜线(\);
2.把它放在\Q(引用开始) 和 \E(引用结束)之间。在使用这种技术时,\Q 和\E能被放于表达式中的任何位置
5.字符类匹配
如果你曾看过Pattern类的说明,会看到一些构建正则表达式的概述。在这一节中你会发现一下的一些表达式:
字符类
[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]]
除 b 和 c 之外的 a 到 z 字符:[ad-z](差集)
[a-z&&[^m-p]]
a 到 z,并且不包括 m 到 p:[a-lq-z](差集)
左边列指定正则表达式构造,右边列描述每个构造的匹配的条件
注意:"字符类(character class)"这个词中的"类(class)"指的并不是一个.class文件。在正则表达式的语义中,字符类是指放在方框号里的字符集,指定了一些字符中的一个能被给定的字符串所匹配。
5.1 简单类(Simple Classes)
字符类最基本的格式是把一些字符放到一个方框号内。例如:正则表达式[bcr]at 会匹配"bat"、"cat"或者"rat",这是由于其定义了一个字符类(接受"b","c"或"r"中的一个字符)作为它的首字符。
Enter your regex: [bcr]at
Enter input string to search: bat
I found the text "bat" starting at index 0 and ending at index 3.
Enter your regex: [bcr]at
Enter input string to search: cat
I found the text "cat" starting at index 0 and ending at index 3.
Enter your regex: [bcr]at
Enter input string to search: rat
I found the text "rat" starting at index 0 and ending at index 3.
在上面的例子中,在第一个字符匹配字符类中所定义字符类中的一个时,整个匹配就是成功的。
5.1.1 否定匹配
要匹配除那些列表之外所有的字符时,可以在字符类的开始处加上^元字符,这种就被称为否定(negation).
Enter your regex: [^bcr]at
Enter input string to search: bat
No match found.
Enter your regex: [^bcr]at
Enter input string to search: cat
No match found.
Enter your regex: [^bcr]at
Enter input string to search: hat
I found the text "hat" starting at index 0 and ending at index 3.
在输入字符串中的第一个字符不包括在字符类中所定义字符中的一个时,匹配是成功的。
5.1.2 范围
有时会想要定义一个包含范围的字符类,诸如,"a到h"的字母或者是"1"到"5"的数字。指定一个范围,只要在匹配的首字符和末字符间插入-元字符,比如:[1-5] 或者是 [a-h] 。也可以在类里每个的边上放置不同的范围来提高匹配的可能性,例如:[a-zA-Z]将会匹配a到z(小写字母)或者A到Z(大写字母)中任何一个字符。
下面是一些范围和否定的例子:
Enter your regex: [a-c]
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
Enter your regex: [a-c]
Enter input string to search: b
I found the text "b" starting at index 0 and ending at index 1.
Enter your regex: [a-c]
Enter input string to search: c
I found the text "c" starting at index 0 and ending at index 1.
Enter your regex: [a-c]
Enter input string to search: d
No match found.
Enter your regex: foo[1-5]
Enter input string to search: foo1
I found the text "foo1" starting at index 0 and ending at index 4.
Enter your regex: foo[1-5]
Enter input string to search: foo5
I found the text "foo5" starting at index 0 and ending at index 4.
Enter your regex: foo[1-5]
Enter input string to search: foo6
No match found.
Enter your regex: foo[^1-5]
Enter input string to search: foo6
I found the text "foo6" starting at index 0 and ending at index 4.
5.1.3 并集
可以使用并集(union)来建一个由两个或两个以上字符类所组成的单字符类。构建一个并集,只要在一个字符类的边上嵌套另外一个,比如:[0-4[6-8]],这种奇特方式构建的并集字符类,可以匹配0,1,2,3,4,6,7,8这几个数字。
Enter your regex: [0-4[6-8]]
Enter input string to search: 0
I found the text "0" starting at index 0 and ending at index 1.
Enter your regex: [0-4[6-8]]
Enter input string to search: 5
No match found.
Enter your regex: [0-4[6-8]]
Enter input string to search: 6
I found the text "6" starting at index 0 and ending at index 1.
Enter your regex: [0-4[6-8]]
Enter input string to search: 8
I found the text "8" starting at index 0 and ending at index 1.
Enter your regex: [0-4[6-8]]
Enter input string to search: 9
No match found.
5.1.4 交集
建一个仅仅匹配自身嵌套类中公共部分字符的字符类时,可以像[0-9&&[345]]中那样使用&&.这种方式构建出来的交集(intersection)简单字符类,仅仅以匹配两个字符类的3,4,5共有部分。
Enter your regex: [0-9&&[345]]
Enter input string to search: 3
I found the text "3" starting at index 0 and ending at index 1.
Enter your regex: [0-9&&[345]]
Enter input string to search: 4
I found the text "4" starting at index 0 and ending at index 1.
Enter your regex: [0-9&&[345]]
Enter input string to search: 5
I found the text "5" starting at index 0 and ending at index 1.
Enter your regex: [0-9&&[345]]
Enter input string to search: 2
No match found.
Enter your regex: [0-9&&[345]]
Enter input string to search: 6
No match found.
下面演示两个范围交集的例子:
Enter your regex: [2-8&&[4-6]]
Enter input string to search: 3
I found the text "3" starting at index 0 and ending at index 1.
Enter your regex: [2-8&&[4-6]]
Enter input string to search: 4
I found the text "4" starting at index 0 and ending at index 1.
Enter your regex: [2-8&&[4-6]]
Enter input string to search: 5
I found the text "5" starting at index 0 and ending at index 1.
Enter your regex: [2-8&&[4-6]]
Enter input string to search: 6
I found the text "6" starting at index 0 and ending at index 1.
Enter your regex: [2-8&&[4-6]]
Enter input string to search: 7
No match found.
5.1.5 差集
最后,可以使用差集(subtraction)来否定一个或多个嵌套的字符类,比如:[0-9&&[^345]], 这个是构建一个匹配除3,4,5之外所有0-9间数字的简单字符类。
Enter your regex: [0-9&&[^345]]
Enter input string to search: 2
I found the text "2" starting at index 0 and ending at index 1.
Enter your regex: [0-9&&[^345]]
Enter input string to search: 3
No match found.
Enter your regex: [0-9&&[^345]]
Enter input string to search: 4
No match found.
Enter your regex: [0-9&&[^345]]
Enter input string to search: 5
No match found.
Enter your regex: [0-9&&[^345]]
Enter input string to search: 6
I found the text "6" starting at index 0 and ending at index 1.
Enter your regex: [0-9&&[^345]]
Enter input string to search: 9
I found the text "9" starting at index 0 and ending at index 1.
到此为止,已经涵盖了如何建立字符类的部分。
6.预定义字符类
Pattern的API包有许多有用的预定义字符类(predefined character classes),提供了常用正则表达式的简写形式
预定义字符类
.
任何字符(匹配或者不匹配行结束符)
\d
数字字符:[0-9]
\D
非数字字符:[^0-9]
\s
空白字符:[\t\n\x0B\f\r]
\S
非空白字符:[^\s]
\w
单词字符:[a-zA-Z_0-9]
\W
非单词字符:[^\w]
上表中,左列是构造右边字符类的简写形式。例如:\d指的是数字范围(0-9),\w指的是单词字符(任何大小写、下划线或者是数字)。无论何时都有可能使用预定义字符类,它可以使代码更易阅读,更易从难看的字符类中排除错误。
以反斜线(\) 开始的构造称为构造(escaped constructs)。回顾一下在字符串中一节中的转义构造,在那里我们提及了使用反斜线,以及用于引用的\Q和\E。在字符串中使用转义构造,必须在一个反斜线前在增加一个反斜线用于字符串的编译,例如:
private final String REGEX="\\d";
这个例子中\d是正则表达式,另外的那个反斜线是用于代码编译所必须的。但是测试工具读取的表达式,是直接从控制台中输入的,因此不需要那个多出来的反斜线。
下面的例子说明了预定义字符类的用法:
Enter your regex: .
Enter input string to search: @
I found the text "@" starting at index 0 and ending at index 1.
Enter your regex: .
Enter input string to search: 1
I found the text "1" starting at index 0 and ending at index 1.
Enter your regex: .
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
Enter your regex: \d
Enter input string to search: 1
I found the text "1" starting at index 0 and ending at index 1.
Enter your regex: \d
Enter input string to search: a
No match found.
Enter your regex: \D
Enter input string to search: 1
No match found.
Enter your regex: \D
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
Enter your regex: \s
Enter input string to search:
No match found.
Enter your regex: \s
Enter input string to search: a
No match found.
Enter your regex: \s
Enter input string to search: " "
I found the text " " starting at index 1 and ending at index 2.
Enter your regex: \S
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
Enter your regex: \w
Enter input string to search: a
I found the text "a" starting at index 0 and ending at index 1.
Enter your regex: \w
Enter input string to search: !
No match found.
Enter your regex: \W
Enter input string to search: !
I found the text "!" starting at index 0 and ending at index 1.
在开始的三个例子中,正则表达式是最简单的,.("点"元字符)表示"任意字符",因此,在所有的三个例子(随意选取了"@"字符,数字和字母)中都是匹配成功的。在接下来的例子中,都使用了预定义的字符类表格中的单个正则表达式构造。你应该可以根据这张表指出前面每个匹配的逻辑:
\d 匹配数字字符
\s 匹配空白字符
\w 匹配单词字符
也可以使用意思正好相反的大写字母:
\D 匹配非数字字符
\S 匹配非空白字符
\W 匹配非单词字符