Java中正则表达式、模式匹配与信息抽取

时间:2021-10-27 03:23:34

引言

记得几年前在做网页爬虫后的信息抽取时,针对网页源码中隐藏的要提取的信息,比如评论、用户信息等属性信息,直接利用HtmlParser得到。如此做倒是简单,不过利用的是网页的规范的tag标记。其实java中的正则表达式也可以用来实现这一功能。而且对于非tag的一些有规律的系列组合的字符串,正则表达式更能够发挥其卓越的功能。大学时候曾经就接触过正则表达式,不过只是略知皮毛。现在也无心学习,上面的链接网页有一个比较清晰的介绍可供参考。下面只是陈述一下自己在实验过程中利用正则表达式来进行模式匹配以抽取目标信息的尝试及一些简单发现。
 
 
捕获组
 
 
模式中用()来表示捕获组,并且根据圆括号从左到右来编号。一个给定的正则表达式完整部分编号为0,然后()从左到右分别从1开始计数。我们可以得到任意捕获组的内容,下面用一个例子来展示:
 
[java] 
public static void main(String[] args) {  
    // TODO Auto-generated method stub  
    String stmt = "xx[new Date('08/24/2013'), 9.39],[new Date('08/24/2013'), 9.39],";  
    String regex = "\\[(.*?)\\],";  
    Pattern p = Pattern.compile(regex);  
    Matcher m = p.matcher(stmt);  
    System.out.println(m.groupCount());  
    while(m.find()){  
        System.out.println(m.group(0));  
        System.out.println(m.group(1));  
    }  
}  
 
输出结果为:
[plain 
1  
[new Date('08/24/2013'), 9.39],  
new Date('08/24/2013'), 9.39  
[new Date('08/24/2013'), 9.39],  
new Date('08/24/2013'), 9.39  
根据这,我们可以看到整个的表达式为捕获组0,可以匹配输出符合整个表达式模式的串。而()里面的捕获组则得到相应的匹配内容。
 
量词
同样上面的代码,当我们将正则表达式中的?去掉后,输出结果为:
[plain] view plaincopy
1  
[new Date('08/24/2013'), 9.39],[new Date('08/24/2013'), 9.39],  
new Date('08/24/2013'), 9.39],[new Date('08/24/2013'), 9.39  
则发现匹配的是全局部分,也就是所谓的贪婪策略。这就是由于贪婪、勉强和侵占量词的不同。详情可以参考:http://www.java3z.com/cwbwebhome/article/article8/Regex/Java.Regex.Tutorial.html#reg5_3
 
因此,我个人认为如果用来信息抽取可能更多的用的是勉强量词。
 
 
嵌套模式?
假若我们抽取的模式里面包括很多频繁的子模式,是否能够用一个正则表达式来完成呢?比如针对上面的事例,如果将正则表达式修改为
[java] 
String stmt = "xx[[new Date('08/24/2013'), 9.39],[new Date('08/24/2013'), 9.39],];";  
String regex = "\\[(\\[(.*?)\\],)*\\];";  
Pattern p = Pattern.compile(regex);  
Matcher m = p.matcher(stmt);  
System.out.println(m.groupCount());  
while(m.find()){  
    System.out.println(m.group());  
    System.out.println(m.group(0));  
    System.out.println(m.group(1));  
    System.out.println(m.group(2));  
}  
 
目前还没有有效的办法获取最内层捕获组的匹配串,算是一个问题吧?虽然我们可以先用一个正则提取重复部分,然后再利用正则将其分解,一步不行吗?
 
 
Tips
1. .默认并不匹配所有的字符,例如换行空白的就不可以,这时候可以用Pattern p = Pattern.compile(regex,Pattern.DOTALL);来使其匹配所有