分享
 
 
 

Merlin的魔力:用新的正则表达式库解析字符序列

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

虽然 Java 语言以前的版本支持模式匹配,但 StreamTokenizer 和 StringTokenizer 类却很少涉及用模式能够实现的功能。Java 1.4(以及现在的 1.4.1)发行版在 java.util.regex 包中加入了对使用正则表达式的模式匹配的支持。在 Merlin 的魔力系列的这篇文章中,John Zukowski 向您展示了如何用新的正则表达式库解析字符序列,从而使搜索模式的功能更加强大。

解析模式的文本字符串

正则表达式是根据文本匹配模式的方法 ? 类似于编译器生成类文件的工作原理。编译器在源代码中查找各种模式以便将源代码表达式转换为字节码。通过识别这些源代码模式,编译器能够只将有效的源代码表示转换为已编译的类文件。

什么是模式?

在正则表达式的上下文中,模式是字符序列的文本表示法。例如,假如您想知道一个字符序列中是否存在 car 这个词,您会使用模式 car,因为这是精确地表示该字符串的方法。对于更复杂的模式,您可以使用非凡字符作为占位符。假如您不是要搜索 car,而是想搜索以字母 c 开头并以字母 r 结尾的任何文本字符串,您会使用 c*r 模式,其中 * 代表第一个 r 前的任意多个字符。c*r 模式将匹配任何以 c 开头并以 r 结尾的字符串,如 cougar、cavalier 或 chrysler。

如何指定模式表达式

模式匹配的主要部分是关于要使用什么样的表达式。Pattern 先保存要使用的表达式,然后将其传递给 Matcher 类以便在字符序列的上下文中检查其匹配情况。例如,假如您想验证一个电子邮件地址,您可能要检查用户输入是否与这样一个模式匹配 ? 它包含一个字母数字序列,后跟一个 @ 符号,@ 后又跟两组用句点隔开的字符。这可以用表达式 p{Alnum}+@w+.p{Alpha}{2,3} 来表示。(是的,这过于简化了电子邮件地址的结构,可能会排除某些有效的电子邮件地址,但它作为示例已经足够了。)

在讨论模式语言的具体细节之前,我们来仔细看一下 p{Alnum}+@w+.p{Alpha}{2,3}。p{Alnum} 序列表示单个字母数字字符(A 到 Z、a 到 z 或 0 到 9)。p{Alnum} 后面的加号(+)被称为量词(quantifier)。它被应用在表达式的前面部分,表示 p{Alnum} 必须出现一次或更多次。使用星号(*)表示要出现零次或一次以上(含一次)。@ 就是意味着它必须出现在至少一个字母数字字符之后,这样整个模式匹配才能成功。w+ 与 p{Alnum}+ 类似,但添加了下划线(_)。某些序列有多个表达式。反斜杠( .)代表句点。假如前面没有反斜杠,单独一个句点代表任意字符。最后的 p{Alpha}{2, 3} 表示两个或三个字母字符。

只要学会了规范语言,您就能把握模式的所有秘密。我们来看一些更常用的表达式的种类:

文字(Literal):表达式内任何不具有非凡意义的字符都被看作是一个文字,并与自身匹配。

量词(Quantifier):某些字符或表达式,它们被用来计算一个文字或分组可以在字符序列中出现的次数,以便该序列与表达式匹配。分组是由圆括号内的一组字符指定的。

? 表示出现一次或根本不出现

* 表示出现零次或一次以上(含一次)

+ 表示出现一次或多次

字符类(Character class):一个字符类就是方括号内的一个字符集,其中,匹配可以是括号内的任意一个字符。您可以把字符类与量词结合在一起,例如,[acegikmoqsuwy]* 将是只包含字母表中奇数字母的任意字符序列。某些字符类是预先定义的:

d ? 数字(0 到 9)

D -- 非数字

s -- 空白字符,如制表符或换行符

S -- 非空白字符

w -- 单字字符(a 到 z、A 到 Z、0 到 9 以及下划线)

W -- 非单字字符(其它任意字符)

Posix 字符类(Posix character class):某些字符类仅在用于 US-ASCII 比较时才有效。例如:

p{Lower} ? 小写字符

p{Upper} ? 大写字符

p{ASCII} ? 所有 ASCII 字符

p{Alpha} ? 字母字符(p{Lower} 与 p{Upper} 相结合)

p{Digit} ? 从 0 到 9 的数字

p{Alnum} ? 字母数字字符

范围(Range):使用短线(dash)来指定包括一定范围字符的字符类。例如,[A-J] 表示从 A 到 J 的大写字母。

否定(Negation):脱字符(^)否定字符类的内容。例如,[^A-J] 表示除 A 到 J 之外的任何字符。

请参阅 Pattern API 文档(可以从参考资料找到)了解关于序列的其它具体信息。

如何有效地使用模式

既然您已经了解了如何指定模式,我们就来使用它们吧。您需要让 Pattern 类编译它们,如下所示。注重,反斜杠字符()在 String 常量中需要转义。

Pattern pattern = Pattern.compile(

"\p{Alnum}+@\w+\.\p{Alpha}{2,3}");

有了一个编译好的模式后,您可以使用 Pattern 类根据模式把一个输入行分割为一系列单字,或者使用 Matcher 类执行一些更复杂的任务。下面说明了如何分割输入字符序列,其中使用的模式指定了分隔符,而不是字:

String Words[] = pattern.split(input);

假如您想在一个字符序列中多次匹配一个模式,上面的代码片段是一个很好的起点。但假如您想获取特定的输入,您将需要 Pattern 的 matcher() 方法。在给定某个输入时,这个方法将返回适当的 Matcher 类。接着,您使用 Matcher 实例遍历整个结果在输入序列中查找不同的模式匹配,或者使用 Matcher 实例作为查找-替换工具(后一种方法更好):

Matcher matcher = pattern.matcher(input);

要根据整个序列匹配模式,请使用 matches()。要确定是否只有序列的一部分匹配,请使用 find():

if (matcher.find()) {

// Found some string within input sequence

// That matched the compiled pattern

String match = matcher.group();

// Process matching pattern

}

完整的示例

这两个类(Pattern 与 Matcher)就是整个模式匹配库。提出正确的正则表达式,然后使用 Matcher 类的结果,这就是这个模式匹配库要做的全部工作。在针对 Java 语言的关于正则表达式的专门书籍出现之前,请找一本关于 Perl 的好书来进一步了解特定的模式。清单 1 提供了一个完整的示例,该示例将在特定文件中查找从命令行作为输入而传入的最长单词。

清单 1.“最长的单词”示例

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

import java.nio.charset.*;

import java.util.*;

import java.util.regex.*;

public class Longest {

public static void main(String args[]) {

if (args.length != 1) {

System.err.println("Provide a filename");

return;

}

try {

// Map File from filename to byte buffer

FileInputStream input =

new FileInputStream(args[0]);

FileChannel channel = input.getChannel();

int fileLength = (int)channel.size();

MappedByteBuffer buffer = channel.map(

FileChannel.MapMode.READ_ONLY, 0, fileLength);

// Convert to character buffer

Charset charset = Charset.forName("ISO-8859-1");

CharsetDecoder decoder = charset.newDecoder();

CharBuffer charBuffer = decoder.decode(buffer);

// Create line pattern

Pattern linePattern =

Pattern.compile(".*$", Pattern.MULTILINE);

// Create word pattern

Pattern wordBreakPattern =

Pattern.compile("[\p{Punct}\s}]");

// Match line pattern to buffer

Matcher lineMatcher =

linePattern.matcher(charBuffer);

// Holder for longest word

String longest = "";

// For each line

while (lineMatcher.find()) {

// Get line

String line = lineMatcher.group();

// Get array of words on line

String words[] = wordBreakPattern.split(line);

// Look for longest word

for (int i=0, n=words.length; i<n; i++) {

if (words[i].length() > longest.length()) {

longest = words[i];

}

}

}

// Report

System.out.println("Longest word: " + longest);

// Close

input.close();

} catch (IOException e) {

System.err.println("Error processing");

}

}

}

参考资料

请单击文章顶部或底部的讨论参加关于本文的讨论论坛。

请阅读 java.util.regex 包的 API 文档。

请试用面向 Java 版本 1.4 之前的 alphaWorks Regex for Java。

developerWorks Linux 专区发表了一个 Cultured Perl 月刊专栏,这个专栏可能向您提供使用 Java 语言的正则表达式的比较深入的知识。

阅读 John Zukowski 写的 Merlin 技巧全集。

请在 developerWorks Java 技术专区上查找更多的 Java 参考资料。

关于作者

John Zukowski 通过 JZ Ventures, Inc. 从事战略性 Java 咨询,同时还担任一些 jGuru 的由社区推动的 Java 常见问题解答的常驻指导。他最近的著作有 Apress 出版的 Learn Java with JBuilder 6 与 Sybex 出版的 Mastering Java 2: J2SE 1.4 。请通过 jaz@zukowski.net 与他联系。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有