很长时间以来,Unix管理用户使用基于正则表达式的命令或程序,如grep、perl、sed和awk。由于这是一个非常强大的搜索和操纵字符串的手段,Java 1.4向核心API添加了java.util.regex程序包。当然,Java是与平台无关的,这些正则表达式可以运行在任何系统上,而不仅仅是Unix。JDK中包含Regex程序包已有一段时间,但是我仍发现很多Java编程人员从未使用过它。Regex模式是一种有价值的基础工具,可以用于很多类型的文本处理,如匹配、搜索、提取、替换和分析结构化内容。
在Java中,通过使用适当命名的Pattern类可以容易地确定String是否匹配某种模式。模式可以像匹配某个特定的String值那样简单,也可以很复杂,需要采用分组和字符类,如空白、数字、字母或控制符。由于它们是Java字符串并且基于Unicode(统一字符编码),正则表达式也适用于国际化的应用程序。
正则式是最简单的能准确匹配一个给定String的模式。换句话说,模式与所要匹配的文本是等价的。静态的Pattern.matches方法用于比较一个String是否匹配一个给定模式。 以下的代码将检查变量data中的值是否与单词“Java”相匹配:
String data = getStringData(); // populate the String somehow
boolean result = Pattern.matches("Java", data); // is it "Java"?
|
对于直接匹配字符串和简单的模式而言,你很可能不会使用正则表达式,因为这实际上就是低效率版本的"Java".equals(data)。Regex的真正强大之处体现在使用包括字符类和量词(*、+和?)的更复杂的模式上。目前已有很多优秀的有关正则表达式模式的书籍,因此这里只讨论模式的一些基本特性并重点讨论Java的regex类和方法。为了快速了解这些特性,这里给出一些在正则表达式中使用的特殊字符,其中每一个均代表一类字符,在regex术语中它称为字符类:
\d 数字
\D 非数字
\w 单字字符(0–9,A–Z,a–z,_ )
\W 非单字字符
\s 空白(空格符、换行符、回车键、制表符)
\S 非空白
[ ] 由方括号内的一个字符列表创建的自定义字符类
. 匹配任何单个字符(除了换行符)
|
大多数字符在一个模式表达式中代表它们自己,但是一些字符有其特殊含义。上面使用的反斜杠(转义字符)就是一个例子。下面的字符用于控制将一个子模式应用到匹配过程的次数。这些特殊字符的处理方式不同于其他字符:
? 重复前面的子模式零次或一次
* 重复前面的子模式零次或多次
+ 重复前面的子模式一次或多次
|
下面的正则表达式可以匹配任何对先辈的称呼,如father、great-great-grandmother或great-great-great-grandfather。正如下面的示例所示,通过使用括弧中的子表达式可以创建更复杂的正则表达式:
((great–)*grand)?(mother|father)
|
接下来这个模式表达式将会匹配一个以一个数字开头后跟零个或多个非空白字符的任意字符串(例如它将匹配“3”、“5x”和“56abcd9”,而不匹配“8 5”或“hello”):
要谨慎使用regex反斜杠字符,因为在Java中它也是String文字转义字符。如果使用一个String文字来保存正则表达式,将需要通过使用两个反斜杠来转义反斜杠本身。例如:
String digitNonSpacePattern = "\\d\\S*";
String data = getStringData();
boolean isMatch = Pattern.matches(digitNonSpacePattern, data);
|
此外,模式匹配也内置于String类本身。在String类中有一个新的简便方法:matches。可以如下重写以上的代码:
boolean isMatch = getStringData().matches("\\d\\S*");
|
Pattern.matches方法和String的matches方法都适合一次性使用,但是若重复使用它们的效率较低。通过使用静态的Pattern.compile方法创建一个Pattern实例可以得到一个更高效的用于执行多次匹配的编译版本的模式。Pattern对象可以和java.util.regex.Matcher类协同工作。为了执行复杂的匹配,需要创建Matcher(匹配器)。Matcher将一个模式表达式绑定到一个特定的字符串,以便执行更高级的匹配操作。以下的代码段编译了一个匹配仅由单个字符组成的模式:
String data = getStringData();
Pattern namePattern = Pattern.compile("\\w+");
// get a Matcher to apply the pattern to the data
Matcher nameMatcher = namePattern.matcher(data);
boolean isMatch = nameMatcher.matches();
|
要记住matches方法将会对整个输入字符串和模式进行匹配。如果希望检查字符串是否仅以模式开头,则可以使用lookingAt方法:
boolean startsWith = nameMatcher.lookingAt();
|
在以下几个小节中将会讨论其他一些匹配技术,包括查找匹配一个模式的子串以及执行文本替换。