概述
Java 101
正则表达式简化模式匹配的代码
探索在文本处理场合下涉及模式匹配中正则表达式的优雅之处。
概要
文本处理经常涉及的根据一个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;
February 7, 2003
)
By Jeff Friesen ,Translated By humx
文本处理经常的要求依据特定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 (一个在一个或多个文件中匹配正则表达式,为了全局地正则表达式打印的工具。
什么是正则表达式? Java's java.util.regex 包通过Pattern,Matcher类和PatternSyntaxException异常支持pattern matching:
Listing 1 介绍这些类:
Listing 1. RegexDemo.java
// RegexDemo.java 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 输出的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 这个输出展示了两个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:
java RegexDemo [csw] cave
java RegexDemo [csw] cave [csw]中c匹配在cave中的c。没有其它的匹配存在。
java RegexDemo [^csw] cave
java RegexDemo [^csw] cave 匹配在cave中遇到的a, v, 和e。没有其它的匹配存在。
java RegexDemo [a-c] clown
java RegexDemo [a-c] clown 匹配在clown中的c。没有其它的匹配存在。
Tip
通过将它们放置在一起来在一个range character class内联合多个范围。例如:[a-zA-Z] 匹配所有的大写和小写字母。
java RegexDemo [ab[c-e]] abcdef
java RegexDemo [ab[c-e]] abcdef 匹配它们在abcdef中的副本 a, b, c, d, and e。没有其它的匹配存在。
java RegexDemo [aeiouy&&[y]] party
java RegexDemo [aeiouy&&[y]] party 匹配在party中的y。没有其它的匹配存在。
java RegexDemo [a-f&&[^a-c]&&[^e]] abcdefg
java RegexDemo [a-f&&[^a-c]&&[^e]] abcdefg 匹配在abcdefg中的 d 和f。没有其它的匹配存在。
预定义的character classes
一些在regexes 中出现足够次数的character classes 提供了shortcuts。Pattern用预定义的character class提供了这样的shortcuts,如Table 1所示。使用预定义的character classes来简化你的regexes和最小化regex语法错误。
Table 1. 预定义的character classes
Predefined character class
Description
/d
A 数字。 相当于[0-9]。
/D
A 非数字。相当于[^0-9]。
/s
A whitespace character。相当于[ /t/n/x0B/f/r]。
/S
A 非空格字符。相当于[^/s]。
/w
A 一个字符。相当于[a-zA-Z_0-9]。
/W
A 非字符,相当于[^/w]。
随后的命令行示例使用了/w预定义character class来identify 命令行中的所有word characters。
java RegexDemo /w "aZ.8 _"
上边的命令行产生了以下的输出,它展示了句点和space characters 不被考虑为word character:
Regex = /w Note
Pattern的SDK文档引用句点元字符作为匹配除了line terminator,一个或者两个标志一行结束的预定义的标志之外的任何字符,除非 dotall mode (随后讨论)有效。Pattern 识别以下line terminators:
捕获组
Pattern支持在pattern匹配的过程中,一个regex construct 调用capturing group 来保存为了以后recall 的match的字符;此结构是由圆括号包围的字符序列。在捕获的group中的所有字符在匹配的过程中被作为一个单独的单元。例如,(Java) capturing group 结合了字符 J, a, v, 和a为一个单独单元。Capturing group依据在text中Java的出现来匹配Java pattern。每一个match用下一个匹配的Java字符替代了前一个match保存的Java字符。
Capturing groups 在其它capturing groups内被嵌套。例如:在(Java( language)),( language) 在(Java)内嵌套。每一个嵌套或非嵌套的capturing group有它自己的数字,数字从1开始,Capturing 数字从左边至右。在这个例子中,(Java( language))是capturing group 1,( language)是capturing group 2。在(a)(b),(a)是捕获组1,(b)是捕获组2。
每一个capturing group随后通过a back reference来recall保存的match。指定跟随在一个反斜杠后的数字来指示一个capturing group,back reference来 recalls 一个capturing group捕获的文本字符。一个back reference 的出现导致了一个matcher 使用the back reference的 capturing group number来recall捕获组保存的match ,然后使用匹配的字符进行进一步的匹配操作。随后的示例示范了为了检查语法错误进行的text 搜索的用法:
java RegexDemo "(Java( language)/2)" "The Java language language"
这个例子使用(Java( language)/2) regex为了检查语法错误,来检索字符串The Java language language,那里Java直接地在两个连续出现的language之前。Regex 指定了两个capturing groups: number 1 is (Java( language)/2), 它匹配Java language language,number 2 is ( language), 它匹配由language跟随的space characer。/2 back reference recalls number 2's 保存的match,它允许matcher检索空格后跟随language的第二次出现,which 直接地跟随space character and language的第一次出现。随后的输出显示了RegexDemo's matcher 找到了什么:
Regex = (Java( language)/2) 量词
Quantifiers大概是理解起来最让人迷惑的regex 结构。一部分混淆来自于尽力的理解18个量词逻辑(六个基本逻辑被组织为三个主要逻辑)。其它的一个混淆来自于费尽的0长度匹配的理解。一旦你理解了这个概念和18 categories, 大部分(假如不是全部)混淆将消失。
Note
简要地, 着一部分主要讨论18 个quantifier categories 和zero-length 匹配的概念。为了更详尽的讨论和更多示例,请学习The Java Tutoria 的"Quantifiers"部分。
一个quantifier 是一个隐式或显示的为一个pattern绑定一个数量值的正则表达式结构。这个数字值解决定了匹配一个pattern的次数。Pattern的六个基本的quantifiers匹配一个pattern一次或者根本不匹配,0次或者多次,一次或者多次,一个精确的数字次数,至少x次和 至少x次但不超过y次。
六个基本的quantifier categories 在每一个三个主要的类别:greedy, reluctant和 possessive中复制。Greedy quantifiers 尝试找到最长的匹配。与之对照,reluctant quantifiers 尝试找到最短的匹配。Possessive quantifiers 也尝试找到最长的匹配。然而,他们和greedy quantifies在工作方式上不同。尽管greedy 和possessive quantifiers 迫使一个matcher 在进行第一次匹配之前读取整个的text,greedy quantifiers 常常导致为了找到一个match进行多次尝试,然而possessive quantifiers 让一个matcher 仅尝试一个match一次。
随后的示例描述了六种基本的quantifiers 在greedy category类别下,单个fundamental quantifier 在每一个 reluctant 和 possessive categories类别下的行为。这些示例也描述了0匹配的概念:
1. java RegexDemo a? abaa: 使用一个greedy quantifier 来在abaa中匹配a 一次或者根本不匹配。以下是输出结果:
Regex = a? 这个输出展示了五次匹配。尽管第一、三和四次匹配的出现展示了三次匹配中位置并不奇怪,第一、第五次的匹配大概有点奇怪。这个匹配好像指出a匹配b和文本的结束。然而,不是这种情况。a?并不查找b和文本结尾。相反, 它查找a的出现或者缺失。当a? 查找a失败的时候,它以零长度的匹配返回那个事实(a缺失),在零长度那里起始和结束位置的索引相同。Zero-length matches 发生在空文本, 最后一个文本字符之后,或者任何量个字符之间。
2. java RegexDemo a* abaa: 使用一个greedy quantifier在abaa 中匹配a零次或多次。以下是输出结果:
Regex = a* 输出展示了四次匹配。像使用 a?,a* 产生了zero-length 匹配。第三个匹配,a* 匹配了aa, 很有趣。不像 a?,a* 匹配一个或者多个连续的a。
3. java RegexDemo a+ abaa: 使用一个greedy quantifier在abaa 中匹配a一次或多次。以下是输出结果:
Regex = a+ 输出展示了两个匹配 。不像 a? 和 a*,a+ 没有匹配a的却失。因而,没有零长度匹配产生。像 a*,a+匹配了连续的a。
4. java RegexDemo a{2} aababbaaaab: 使用greedy quantifier 来匹配中的每一个 aababbaaaab中的 aa序列。以下是输出结果:
Regex = a{2} 5. java RegexDemo a{2,} aababbaaaab: 使用了greedy quantifier 来匹配在ababbaaaab中两个或更多的匹配,以下是输出结果:
Regex = a{2,} 6. java RegexDemo a{1,3} aababbaaaab: 使用greedy quantifier 来匹配在aababbaaaab中出现的a、aa或者aaa。以下是输出结果:
Regex = a{1,3} 7. java RegexDemo a+? abaa: 使用一个reluctant quantifier 在abaa中一次或多次匹配a。以下是输出结果:
Regex = a+? 不像在第三个例中的greedy变量,reluctant 示例产生了三个单独的匹配,因为reluctant quantifier尽力的查找最短的匹配。
8. java RegexDemo .*+end "This is the end": 使用了possessive quantifier 来匹配在this is the end中的以end结尾的任意字符0次或者多次。以下是输出结果:
Regex = .*+end 由于这个possessive quantifier consume了整个文本,没有留下任何东西来匹配end,它没有产生匹配。相比之下,在java RegexDemo .*end "This is the end" 的greedy quantifier,因为它每次backing off一个字符直到最右端的end匹配,产生了一个匹配。(这个quantifier与greedy的不同就在后者的匹配过程中一旦匹配的字符,在随后的匹配中就不再使用。因此.*这部分正则表达式就匹配了全部的字符串,就没有字符可以与end匹配了。)
Boundary matchers
我们有时想在一行的开始、在单词的边界、文本的结束等等匹配pattern。使用 boundary matcher,一个指定了匹配边界的正则表达式结构,完成这个任务。Table 2 表示了Pattern的边界匹配支持。
Table 2. Boundary matchers
Boundary Matcher
Description
^
一行的开始
$
一行的结束
/b
单词的边界
/B
非单词边界
/A
文本的开始
/G
前一个匹配的结束
/Z
The end of the text (but for the final line terminator, if any)
/z
文本结束
下边的命令行示例使用了^ 边界匹配元字符 ensure 由零个或者多个字符跟随的行开始。
java RegexDemo ^The/w* Therefore
^ 指出了前三个字符必须匹配pattern后的T、h和e字符。可跟随任意数量的字符。以上的命令行产生以下输出:
Regex = ^The/w* 把命令行改为java RegexDemo ^The/w* " Therefore"。发生了什么事?因为在therefore前的一个空格,没有匹配被发现。
Embedded flag expressions
Matcher假设了确定的却省值,例如大小写敏感的匹配。一个程序可以使用an embedded flag expression 来覆盖缺省值,也就是,使用一个正则表达式结构,圆括号元字符包围一个问号元字符后跟小写字母。Pattern认可以下的embedded flag expressions :
Embedded flag expressions 类似于 capturing groups因为两个regex constructs都用圆括号包围字符。不像capturing group,embedded flag expression 没有捕获匹配的字符。因而,一个embedded flag expression是noncapturing group的特例。也就是说,一个不捕获text字符的regex construct ;它指定了由元字符圆括号包围的字符序列。在Pattern's SDK 文档中出现了一些noncapturing groups。
Tip
为了在正则表达式中指定多个embedded flag 表达式。或者吧它们并排的放在一起 (e.g., (?m)(?i)) 或者 把它们的小写字母并排的放在一起 (e.g., (?mi))。
探索java.util.regex 类的方法
java.util.regex包的三个类提供了为帮我书写更健壮的正则表达式代码和创建强大的text处理工具许多的方法。 我们从Pattern类开始探索这些方法。
Note
你也可以explore CharSequence 接口的当你创建一个新的字符序列类要实现的方法。仅实现 CharSequence 接口的类是java.nio.CharBuffer, String, 和 StringBuffer。
Pattern 方法
除非代码将一个string编译为Pattern对象一个regex表达式式没有用处的。用以下编辑方法中的一个完成这个任务:
假如需要,通过调用以下方法可以得到一个Pattern对象的flag和最初的被编译为对象的正则表达式:
在创建一个Pattern对象后,你一般的通过调用Pattern的公有方法matcher(CharSequence text)获得一个Matcher对象。这个方法需要一个简单的,实现了CharSequence接口的文本对象参数。获得的对象在pattern匹配的过程中扫描输入的文本对象。例如:Pattern p = Pattern.compile ("[^aeiouy]"); Matcher m = p.matcher ("This is a test."); 获得一个在text中匹配所有非元音字母的matcher。
当你想检查一个pattern是否完全的匹配一个文本序列的时候创建Pattern和Matcher对象是令人烦恼的。幸运的是,Pattern提供了一个方便的方法完成这个任务;public static boolean matches(String regex, CharSequence text)。当且仅当整个字符序列匹配regex的pattern的场合下静态方法返回布尔值true。例如:System.out.println (Pattern.matches ("[a-z[//s]]*", "all lowercase letters and whitespace only"));返回布尔值true, 指出仅空格字符和小写字符在all lowercase letters and whitespace only中出现。
书写代码将text分成它的组成部分(例如雇员记录文件到一个字段的set) 是许多开发者发现乏味的任务。Pattern 通过提供一对字符分割方法来减轻那种tedium。
假如你想一个拆分雇员记录,包含了姓名,年龄,街道和工资,为它的组成部分。以下的代码用split(CharSequence text)方法完成了这个任务:
Pattern p = Pattern.compile (",//s"); The code fragment above specifies a regex that matches a comma character immediately followed by a single-space character and produces the following output:
John Doe Note
String合并了三个方便的方法调用它们等价的Pattern方法: public boolean matches(String regex), public String [] split(String regex), and public String [] split(String regex, int limit)。
Matcher 方法
Matcher对象支持不同类型的pattern匹配操作,例如扫描text查找下一个match;尝试根据一个pattern来匹配整个文本;根据一个pattern尝试匹配部分text。用以下的方法完成这些任务:
不像Pattern对象,Matcher 包含了状态信息。有时,你在一个pattern 匹配后想reset一个matcher清除那些信息。下边的方法reset了一个matcher:
一个matcher的append position 决定了matcher的text的追加到一个StringBuffer对象中的开始位置。以下的方法使用了append position:
随后的例子调用appendReplacement(StringBuffer sb, String replacement) 和 appendTail(StringBuffer sb) 方法来替换所有在one cat, two cats, or three cats on a fence 中出现的cat为caterpillar。一个capturing group 和 在replacement中的capturing group的引用允许在每一个cat匹配后插入erpillar:
Pattern p = Pattern.compile ("(cat)"); 此示例产生如下输出:
one caterpillar, two caterpillars, or three caterpillars on a fence
其它的两个替换方法使用替换的文本替换第一个match和所有的match成为可能:
正则表达式/s+ 探测在文本中出现的一次或多次出现的空格。随后的例子使用了这个regex 并调用了replaceAll(String replacement) 方法来从text删除duplicate whitespace :
Pattern p = Pattern.compile ("//s+"); 此示例产生如下输出:
Remove the duplicate whitespace.
Listing 1 包含了System.out.println ("Found " + m.group ());. 注意方法调用group()。此方法是capturing group-oriented 的Matcher方法:
以下代码示范了the capturing group 方法:
Pattern p = Pattern.compile ("(.(.(.)))"); The example produces the following output:
3 Capturing group 数字0 保存了previous match 且与has nothing to do with whether 一个capturing group在一个pattern中出现与否没有任何关系。也就是 is (.(.(.)))。其它的三个capturing groups捕获了previous match属于这个capturing groups的字符。例如,number 2, (.(.)), 捕获 bc; and number 3, (.), 捕获 c.
在我们离开讨论Matcher的方法之前,我们将examine四个match位置方法:
下边的示例示范了两个match position 方法,为capturing group number 2报告起始/结束match 位置:
Pattern p = Pattern.compile ("(.(.(.)))"); The example produces the following output:
Found bc 输出show我们仅仅对与capturing group number 2相关的matcher感兴趣,也就是这些匹配的起始结束位置。
Note
String 引入了两个方便的和调用Matcher等价的方法:public String replaceFirst(String regex, String replacement) 和 public String replaceAll(String regex, String replacement)。
PatternSyntaxException methods
Pattern的方法当它们发现非法的正则表达式语法错误的时候抛出PatternSyntaxException 异常。一个异常处理器可以调用PatternSyntaxException 的方法来获得抛出的关于语法错误的PatternSyntaxException 对象的信息。
因为PatternSyntaxException 从java.lang.RuntimeException继承而来,代码不需要指定错误handler。This proves appropriate when regexes are known to have correct patterns。但当有潜在的pattern语法错误存在的时候,一个异常handler是必需的。因而,RegexDemo的源代码(参看 Listing 1) 包含了try { ... } catch (ParseSyntaxException e) { ... },它们调用了PatternSyntaxException四个异常方法中的每一个来获得非法pattern的信息。
什么组成了非法的pattern?在embedded flag expression 中没有指定结束的元字符结束符号就是一个例。假如你执行java RegexDemo (?itree Treehouse。此命令的非法正则表达式(?tree pattern 导致 p = Pattern.compile (args [0]); 抛出PatternSyntaxException 异常。你将看到如下输出:
Regex syntax error: Unknown inline modifier near index 3 Note
public PatternSyntaxException(String desc, String regex, int index) 构造函数让你创建你自己的PatternSyntaxException对象, That constructor comes in handy should you ever create your own preprocessing compilation method that recognizes your own pattern syntax, translates that syntax to syntax recognized by Pattern's compilation methods, and calls one of those compilation methods. If your method's caller violates your custom pattern syntax, you can throw an appropriate PatternSyntaxException object from that method。
一个正则表达式应用实践
Regexes let you create powerful text-processing applications. One application you might find helpful extracts comments from a Java, C, or C++ source file, and records those comments in another file. Listing 2 presents that application's source code:
Listing 2. ExtCmnt.java
// ExtCmnt.java 在创建Pattern 和Matcher 对象之后,ExtCmnt 逐行的读取一个文本文件的内容。对于每一行,matcher尝试匹配pattern的行,鉴别是一个单行的注释或者多行的注释在一行中出现。假如一行匹配pattern,ExtCmnt 将此行写入另外一个文本文件中。例如,java ExtCmnt ExtCmnt.java out 读取ExtCmnt.java 文件的每一行,根据pattern来尝试着一行,将匹配的行输出到名叫out的文件。 (不要担心理解文件的读写逻辑。我将在将来的文章中explore这些代码。) 在ExtCmnt执行完成,out 文件包含了以下行:
// ExtCmnt.java 这个输出显示ExtCmnt 并不完美:p = Pattern.compile (".*///*.*//*/|.*//.*$"); 没有描绘一个注释。出现在out中的行因为ExtCmnt的matcher匹配了//字符。
关于pattern ".*///*.*//*/|.*//.*$"由一些有趣的事,竖线元字符metacharacter (|)。依照SDK documentation,圆括号元字符在capturing group和 竖线元字符是逻辑操作符号。vertical bar 描述了一个matcher,它使用操作符左侧的正则表达式结构来在matcher的文本中定为一个match。假如没有match存在,matcher使用操作符号右侧的正则表达式进行再次的匹配尝试。
温习
尽管正则表达式简化了在text处理程序中pattern匹配的代码,除非你理解它们,否则你不能有效的在你的程序中使用正则表达式。这篇文章通过介绍给你regex terminology,the java.util.regex 包和示范regex constructs的程序来让你对正则表达式有一个基本的理解。既然你对regexes有了一个基本的理解,建立在通过阅读additional articles (see Resources)和学习java.util.regex's SDK 文档,那里你可以学习更多的regex constructs ,例如POSIX (Portable Operating System Interface for Unix) 字符类。
我鼓励你用这篇文章中或者其它以前文章中资料中问题email me。(请保持问题和这个栏目讨论的文章相关性。)你的问题和我的回答将出现在相关的学习guides中。)
After writing Java 101 articles for 28 consecutive months, I'm taking a two-month break. I'll return in May and introduce a series on data structures and algorithms.
About the author
Jeff Friesen has been involved with computers for the past 23 years. He holds a degree in computer science and has worked with many computer languages. Jeff has also taught introductory Java programming at the college level. In addition to writing for JavaWorld, he has written his own Java book for beginners—Java 2 by Example, Second Edition (Que Publishing, 2001; ISBN: 0789725932)—and helped write Using Java 2 Platform, Special Edition (Que Publishing, 2001; ISBN: 0789724685). Jeff goes by the nickname Java Jeff (or JavaJeff). To see what he's working on, check out his Website at http://www.javajeff.com.
Resources
A regular expression,也被known as regex or regexp,是一个描述了一个字符串集合的pattern(template)。这个pattern决定了什么样的字符串属于这个集合,它由文本字符和元字符(metacharacters,由有特殊的而不是字符含义的字符)组成。为了识别匹配的检索文本的过程—字符串满足一个正则表达式—称作模式匹配(pattern matching)。
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 ();
}
}
Text = applet
Found apple
starting at index 0 and ending at index 5
Text = The quick brown fox jumps over the lazy ox.
Found fox
starting at index 16 and ending at index 19
Found ox
starting at index 39 and ending at index 42
Text = aZ.8 _
Found a
starting at index 0 and ending at index 1
Found Z
starting at index 1 and ending at index 2
Found 8
starting at index 3 and ending at index 4
Found _
starting at index 5 and ending at index 6
Text = The Java language language
Found Java language language
starting at index 4 and ending at index 26
Text = abaa
Found a
starting at index 0 and ending at index 1
Found
starting at index 1 and ending at index 1
Found a
starting at index 2 and ending at index 3
Found a
starting at index 3 and ending at index 4
Found
starting at index 4 and ending at index 4
Text = abaa
Found a
starting at index 0 and ending at index 1
Found
starting at index 1 and ending at index 1
Found aa
starting at index 2 and ending at index 4
Found
starting at index 4 and ending at index 4
Text = abaa
Found a
starting at index 0 and ending at index 1
Found aa
starting at index 2 and ending at index 4
Text = aababbaaaab
Found aa
starting at index 0 and ending at index 2
Found aa
starting at index 6 and ending at index 8
Found aa
starting at index 8 and ending at index 10
Text = aababbaaaab
Found aa
starting at index 0 and ending at index 2
Found aaaa
starting at index 6 and ending at index 10
Text = aababbaaaab
Found aa
starting at index 0 and ending at index 2
Found a
starting at index 3 and ending at index 4
Found aaa
starting at index 6 and ending at index 9
Found a
starting at index 9 and ending at index 10
Text = abaa
Found a
starting at index 0 and ending at index 1
Found a
starting at index 2 and ending at index 3
Found a
starting at index 3 and ending at index 4
Text = This is the end
Text = Therefore
Found Therefore
starting at index 0 and ending at index 9
String [] fields = p.split ("John Doe, 47,
Hillsboro Road
, 32000");
for (int i = 0; i < fields.length; i++)
System.out.println (fields [i]);
47
Hillsboro Road
32000
Matcher m = p.matcher ("one cat, two cats, or three cats on a fence");
StringBuffer sb = new StringBuffer ();
while (m.find ())
m.appendReplacement (sb, "$1erpillar");
m.appendTail (sb);
System.out.println (sb);
Matcher m = p.matcher ("Remove the /t/t duplicate whitespace. ");
System.out.println (m.replaceAll (" "));
Matcher m = p.matcher ("abc");
m.find ();
System.out.println (m.groupCount ());
for (int i = 0; i <= m.groupCount (); i++)
System.out.println (i + ": " + m.group (i));
0: abc
1: abc
2: bc
3: c
Matcher m = p.matcher ("abcabcabc");
while (m.find ())
{
System.out.println ("Found " + m.group (2));
System.out.println (" starting at index " + m.start (2) +
" and ending at index " + m.end (2));
System.out.println ();
}
starting at index 1 and ending at index 3
Found bc
starting at index 4 and ending at index 6
Found bc
starting at index 7 and ending at index 9
(?itree
^
Error description: Unknown inline modifier
Error index: 3
Erroneous pattern: (?itree
import java.io.*;
import java.util.regex.*;
class ExtCmnt
{
public static void main (String [] args)
{
if (args.length != 2)
{
System.err.println ("usage: java ExtCmnt infile outfile");
return;
}
Pattern p;
try
{
// The following pattern lets this extract multiline comments that
// appear on a single line (e.g., /* same line */) and single-line
// comments (e.g., // some line). Furthermore, the comment may
// appear anywhere on the line.
p = Pattern.compile (".*///*.*//*/|.*//.*$");
}
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;
}
BufferedReader br = null;
BufferedWriter bw = null;
try
{
FileReader fr = new FileReader (args [0]);
br = new BufferedReader (fr);
FileWriter fw = new FileWriter (args [1]);
bw = new BufferedWriter (fw);
Matcher m = p.matcher ("");
String line;
while ((line = br.readLine ()) != null)
{
m.reset (line);
if (m.matches ()) /* entire line must match */
{
bw.write (line);
bw.newLine ();
}
}
}
catch (IOException e)
{
System.err.println (e.getMessage ());
return;
}
finally // Close file.
{
try
{
if (br != null)
br.close ();
if (bw != null)
bw.close ();
}
catch (IOException e)
{
}
}
}
}
// The following pattern lets this extract multiline comments that
// appear on a single line (e.g., /* same line */) and single-line
// comments (e.g., // some line). Furthermore, the comment may
// appear anywhere on the line.
p = Pattern.compile (".*///*.*//*/|.*//.*$");
if (m.matches ()) /* entire line must match */
finally // Close file.
http://www.javaworld.com/javaworld/jw-02-2003/java101/jw-0207-java101.zip
http://www.javaworld.com/javaworld/jw-02-2003/jw-0207-java101guide.html
http://www-106.ibm.com/developerworks/java/library/j-mer0827/
http://www.javaworld.com/javaworld/jw-07-2001/jw-0713-regex.html
http://developer.java.sun.com/developer/technicalArticles/releases/1.4regex/
http://www.onjava.com/pub/a/onjava/excerpt/javanut4_ch04
http://java.sun.com/docs/books/tutorial/extra/regex/index.html
http://www.wikipedia.org/wiki/Regular_expression
http://www.javaworld.com/javaworld/jw-01-2003/jw-0103-java101.html?
http://www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html
http://www.javaworld.com/channel_content/jw-core-index.shtml
http://forums.devworld.com/webx?50@@.ee6b804
http://www.javaworld.com/javaworld/javaqa/javaqa-index.html
http://www.javaworld.com/javaworld/javatips/jw-javatips.index.html
http://www.javaworld.com/subscribe
最后
以上就是细腻小虾米为你收集整理的java正则表达式; regular expression 的全部内容,希望文章能够帮你解决java正则表达式; regular expression 所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复