Java 101 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
正则表达式简化模式匹配的代码
探索在文本处理场合下涉及模式匹配中正则表达式的优雅之处。
概要
文本处理经常涉及的根据一个 pattern 的匹配。尽管 java 的 character 和 assorted 的 String 类提供了 low-level 的 pattern-matching 支持,这种支持一般带来了复杂的代码。为了帮助你书写简单的 pattern-matching 代码, java 提供了 regular expression 。在介绍给你术语和 java.util.regex 包之后, Jeff Friesen explores 了许多那个包的 Pattern 类支持的正则表达式结构。然后他 examines 了 Pattern 的方法和附加的 java.util.regex 类。作为结束,他提供了一个正则表达式的实践应用。
为察看术语列表,提示与警告,新的 homework ,上个月 homework 的回答,这篇文章的相关材料,请访问 study guide . ( 6,000 words; <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><date year="2003" day="7" month="2"><b><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: black; FONT-FAMILY: Verdana; mso-bidi-font-family: SimSun; mso-font-kerning: 0pt">February 7, 2003</span></b></date> )
By Jeff Friesen , Translated By humx
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 453.75pt; HEIGHT: 1.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://www.javaworld.com/images/rule_ltblue.gif" src="file:///C:%5CDOCUME~1%5Chumi%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png"><font color="#990033"></font></imagedata></shape> 文本处理经常的要求依据特定 pattern 匹配的代码。它能让文本检索, email header 验证,从普通文本的自定义文本的创建(例如,用 "Dear Mr. Smith" 替代 "Dear Customer" ),等等成为可能。 Java 通过 character 和 assorted string 类支持 pattern matching 。由于 low-level 的支持一般带来了复杂的 pattern-matching 代码, java 同时提供了 regular expression 来简代码。
Regular expressions 经常让新手迷惑。然而 , 这篇文章驱散了大部分混淆。在介绍了 regular expression 术语, java.util.regex 包中的类 , 和一个 regular expression constructs 的示例程序之后 , 我 explore 了许多 Pattern 类支持的 regular expression constructs 。我也 examine 了组成 Pattern 和 java.util.regex 包中其它类的方法。一个 practical 的正则表达式的应用程序结束了我的讨论。
Note
|
Regular expressions 的漫长历史开始于计算机科学理论领域自动控制原理和 formal 语言理论。它的历史延续到 Unix 和其它的操作系统,在那里正则表达式被经常用作在 Unix 和 Unix-like 的工具中:像 awk (一个由其创作者, Aho, Weinberger, and Kernighan ,命名,能够进行文本分析处理的编程语言) , emacs ( 一个开发工具 ) ,和 grep ( 一个在一个或多个文件中匹配正则表达式,为了全局地正则表达式打印的工具。
|
什么是正则表达式
?
A
regular expression
,
也被
known as regex or regexp
,是一个描述了一个字符串集合的
pattern
(template)
。这个
pattern
决定了什么样的字符串属于这个集合,它由文本字符和元字符(
metacharacters
,
由
有特殊的而不是字符含义的字符)组成。为了识别
匹配
的检索文本的过程
—
字符串满足一个正则表达式
—
称作模式匹配(
pattern matching
)。
Java's java.util.regex 包通过 Pattern , Matcher 类和 PatternSyntaxException 异常支持 pattern matching :
-
Pattern
对象,被
known as patterns
,是编译的正则表达式。
-
Matcher
对象,或者
matchers
,
在
,实现了
java.lang.CharSequence
接口并作为文本
source
的字符序列中定位解释
matchers
的引擎。
-
PatternSyntaxException
对象描述非法的
regex patterns
。
Listing 1 介绍这些类:
Listing 1. RegexDemo.java
// RegexDemo.java
import java.util.regex.*;
class RegexDemo {
public static void main (String [] args) {
if (args.length != 2)
System.err.println ("java RegexDemo regex text");
return;
}
Pattern p;
try {
p = Pattern.compile (args [0]);
}
catch (PatternSyntaxException e) {
System.err.println ("Regex syntax error: " + e.getMessage ());
System.err.println ("Error description: " + e.getDescription ());
System.err.println ("Error index: " + e.getIndex ());
System.err.println ("Erroneous pattern: " + e.getPattern ());
return;
}
String s = cvtLineTerminators (args [1]);
Matcher m = p.matcher (s);
System.out.println ("Regex = " + args [0]);
System.out.println ("Text = " + s);
System.out.println ();
while (m.find ()) {
System.out.println ("Found " + m.group ());
System.out.println ("starting at index " + m.start () +
" and ending at index " + m.end ());
System.out.println ();
}
}
// Convert \n and \r character sequences to their single character
// equivalents
static String cvtLineTerminators (String s) {
StringBuffer sb = new StringBuffer (80);
int oldindex = 0, newindex;
while ((newindex = s.indexOf ("\\n", oldindex)) != -1){
sb.append (s.substring (oldindex, newindex));
oldindex = newindex + 2;
sb.append ('\n');
}
sb.append (s.substring (oldindex));
s = sb.toString ();
sb = new StringBuffer (80);
oldindex = 0;
while ((newindex = s.indexOf ("\\r", oldindex)) != -1){
sb.append (s.substring (oldindex, newindex));
oldindex = newindex + 2;
sb.append ('\r');
}
sb.append (s.substring (oldindex));
return sb.toString ();
}
}
RegexDemo's public static void main(String [] args) 方法 validates 两个命令行参数:一个指出正则表达式,另外一个指出文本。在创建一个 pattern 之后,这个方法转换所有的文本参数, new-line and carriage-return line-terminator 字符序列为它们的实际 meanings 。例如,一个 new-line 字符序列 ( 由反斜杠后跟 n 表示 ) 转换成一个 new-line 字符(用数字表示为 10 )。在输出了 regex 和被转换的命令行文本参数之后, main(String [] args) 方法从 pattern 创建了一个 matcher ,它随后查找了所有的 matches 。对于每一个 match ,它所出现的字符和信息的位置被输出。
为了完成模式匹配, RegexDemo 调用了 java.util.regex 包中类的不同的方法。不要使你自己现在就理解这些方法;我们将在后边的文章探讨它们。更重要的是,编译 Listing 1: 你需要 RegexDemo.class 来探索 Pattern's regex 结构。
探索 Pattern's regex 构造
Pattern's SDK 文档提供了一部分正则表达式结构的文档。除非你是一个 avid 正则表达式使用者,一个最初的那段文档的阅读会让你迷惑。什么是 quantifiers , greedy 之间的不同是什么 , reluctant, 和 possessive quantifiers? 什么是 character classes , boundary matchers , back references, 和 embedded flag expressions? 为了回答这些和其它的问题,我们探索了许多 Patter 认可的 regex constructs 或 regex pattern 种类。我们从最简单的 regex construct 开始: literal strings 。
Caution
|
不要认为 Pattern 和 Perl5 的正则表达式结构是一样的。尽管他们有很多相同点,他们也有许多,它们支持的 metacharacters 结构的不同点。 ( 更多信息,察看在你的平台上的你的 SDK Pattern 类的文档。 )
|
Literal strings
当你在字处理软件的检索对话框输入一个你指定一个 literal string 的时候,你就指定了一个 regex expression construct 。执行以下的 RegexDemo 命令行来察看一下这个 regex construct 的动作:
java RegexDemo apple applet
上边的这个命令行确定了 apple 作为一个包含了字符 a, p, p, l, and e (依次)的字符 regex construct 。 这个命令行同时也确定了 applet 作为 pattern-matching 的文本。执行命令行以后,看到以下输出:
Regex = apple
Text = applet
Found apple
starting at index 0 and ending at index 5
输出的 regex 和 text 命令行,预示着在 applet 中一个 applet 的成功的匹配,并表示了匹配的开始和结束的索引:分别为 0 和 5 。开始索引指出了一个 pattern match 出现的第一个文本的开始位置,结束索引指明了这个 match 后的第一个 text 的位置。换句话说,匹配的 text 的范围包含在开始索引和去掉结束索引之间(不包含结束索引)。
Metacharacters
尽管 string regex constructs 是有用的,更强大的 regex contsruct 联合了文本字符和 元字符 。例如,在 a.b ,这个句点 metacharacter (.) 代表在 a 个 b 之间出现的任何字符。 为了察看元字符的动作, 执行以下命令行:
java RegexDemo .ox "The quick brown fox jumps over the lazy ox."
以上命令指出 .ox 作为 regex ,和 The quick brown fox jumps over the lazy ox. 作为文本源 text 。 RegexDemo 检索 text 来匹配以任意字符开始以 ox 结束的 match ,并产生如下输出:
Regex = .ox
Text = The quick brown fox jumps over the lazy ox.
Found fox
starting at index 16 and ending at index 19
Foundox
starting at index 39 and ending at index 42
这个输出展示了两个 matches:fox 和 ox 。 . metacharacter 在第一个 match 中匹配 f ,在第二个 match 中匹配空格。
假如我们用前述的 metacharacter 替换 .ox 会怎么样呢?也就是,我们指定 java RegexDemo . "The quick brown fox jumps over the lazy ox." 会有什么样的输出,因为 period metacharacter 匹配任何字符, RegexDemo 在命令行输出每一个匹配字符,包括结尾的 period 字符。
Tip
|
为了指定 . 或者任何的元字符作为在一个 regex construct 作为 literal character , 引用 — 转换 meta 状态到 literal status— 用以下两种方法之一:
在每种情形下,不要忘记在 string literal (例如: String regex = \\.;
)中出现时(像 \\. or \\Q.\\E )的双倍的反斜杠。不要在当它在命令行参数中出现的时候用双倍的反斜杠。
|
Character classes
有时我们限定产生的 matches 到一个特定的字符集和。例如,我们可以检索元音 a, e, i, o, and u ,任何一个元音字符的出现都以为着一个 match 。 A character 类, 通过在方括号之间的一个字符集和指定的 regex construct ,帮我们完成这个任务。 Pattern 支持以下的 character classes :
-
简单字符
:
支持被依次放置的字符串并仅匹配这些字符。例如:
[abc]
匹配字符
a, b, and c
。以下的命令行提供了另外一个示例:
java RegexDemo [csw] cave
java RegexDemo [csw] cave [csw] 中 c 匹配在 cave 中的 c 。没有其它的匹配存在。
-
否定
:
以
^ metacharacter
元字符开始且仅匹配没有在
class
中出现的字符。例如:
[^abc]
匹配所有除了
a, b,
和
c
以外的字符,以下的命令行提供了另外一个示例:
java RegexDemo [^csw] cave
java RegexDemo [^csw] cave 匹配在 cave 中遇到的 a, v, 和 e 。没有其它的匹配存在。
-
范围
:
包含在元字符(
-
)左侧的字符开始,元字符(
-
)右侧字符结束的所有字符。仅匹配在范围内的字符。例如:
[a-z]
匹配所有的小写字母。以下的命令行提供了另外一个示例:
java RegexDemo [a-c] clown
java RegexDemo [a-c] clown 匹配在 clown 中的 c 。没有其它的匹配存在。
margin: 0mm 0mm 0pt; text-align: 发表评论
最新评论
|
评论