posts - 8,  comments - 6,  trackbacks - 0

2.4  使用Regex捕获组
 
在上一节中,介绍了如何使用正则表达式在一个文件中进行搜索以便检索它内部所有的URL。可以使用Matcher类的find、start和end方法来检索匹配的URL字符串。有时有必要进一步处理子串匹配的结果,或是查找附加的子模式。例如,对某个特定区域的URL不进行处理。为了实现此目的,一种强制性的方法是使用另一个Pattern和Matcher对象,代码如下:

// assume urlMatcher instance as in the previous example
while (urlMatcher.find()) {
int startIndex = urlMatcher.start();
int endIndex = urlMatcher.end();
String currentMatch = data.substring(startIndex, endIndex);
// the brute force approach, using a new pattern!
Pattern restricted = Pattern.compile(".*(abc|cbs|nbc)\\.com.*");
Matcher restrictMatcher = restricted.matcher(currentMatch);
if (!restrictMatcher.matches()) {
System.out.println(currentMatch);
}
}
在捕获的URL中匹配域名并不是一个非常高效的方法。由于已经使用find方法完成了提取URL的困难工作,不应该仅仅为了获得结果的一部分而编写另一个regex,并且也不必这样做。正则表达式允许将模式分解成子序列。使用圆括号,将以后要用到的模式部分括起来,这样,我们就可以忽略其余部分单独读取这些部分的值。重写URL模式以使域名可以与URL的其他部分相分离:

String urlPattern =
"(http|https|ftp)://([a-zA-Z0-9-\\.]+)[/\\w\\.\\-\\+\\?%=&;:,#]*";
当在模式中存在用括号括起来的组时,可以分别检索每个组的匹配值。从最左边的组开始编为1,然后依次对每对括号相对应的组进行编号。在上面的模式中,第一组是协议(如http),第二组是域名。为了在匹配的字符串中访问组,可以使用Matcher的group方法。下面的代码示例从每个URL中检索域名并显示它们的值:

String data = getStringData(); // load the document
String urlString =
"(http|https|ftp)://([a-zA-Z0-9-\\.]+)[/\\w\\.\\-\\+\\?%=&;:,#]*";
Pattern urlPattern = Pattern.compile(urlString);
Matcher urlMatcher = urlPattern.matcher(data);
// print out the domain from each URL
while (urlMatcher.find()) {
String domain = urlMatcher.group(2); // 2nd group is the domain
System.out.println(domain);
}

保存每个匹配的组以便可以随后引用它们。在一个模式内引用一个以前的匹配组称为逆向引用(backreference)。为了对第三个组进行逆向引用,在模式中包括\3即可。这将会只匹配一个与以前的组相匹配的严格重复的数据。为了说明此问题,考虑一个在文本文件中常见的错误—— 一个句子中意外地重复出现某个常用的单词,如“the”或“of”。

" The the water molecules are made of of hydrogen and oxygen."

下面编写一个模式来找出文件中存在的这些问题。该模式将捕获第一个单词,后跟一些空白符,而其后又跟着匹配第一个单词的重复模式:

String wordPattern = "\\s(of|or|the|to)\\s+\\1[\\s\\.,;]";
该模式匹配情况如下:一个空白字符、特殊的单词列表中的一个单词、更多的空白、再次重复的相同的单词(使用\1逆向引用)以及空白符或标点符号。这种匹配应不区分大小写,以便能够捕获到“The the”以及类似的变型。如以下的代码段所示,该模式不区分大小写,能在一个字符串中查找重复出现的模式:

String data = getStringData();
String patternStr = "\\s(of|or|the|to)\\s+\\1[\\s\\.,;]";
Pattern wordPattern =
Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
Matcher wordMatcher = wordPattern.matcher(data);
while (wordMatcher.find()) {
int start = wordMatcher.start();
String word = wordMatcher.group(1);
// print the index location of the repeated word
System.out.println("Repeated " + word + " starting at " + start);
}

有一种简便和强大的匹配文件中文本的方法,该方法允许使用多个正则表达式来处理文件,本章后面的“使用Scanner类进行语法分析”一节将会讲解此方法。若想了解使用内置索引进行更为复杂的文本搜索的解决方法,请参考第3章中“使用Lucene进行搜索”一节的内容。


只有注册用户登录后才能发表评论。


网站导航:
 

<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

留言簿(1)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜