一个学术搜索的项目,需要用到学者信息的XML数据。之前项目中从dblp网站爬到了各个学者的主页(html格式),比如http://www.informatik.uni-trier.de/~ley/pers/hd/m/Meersman:Robert.html。现在要从这些HTML文件中提取出每个作者的姓名,论文等信息,如下DTD格式的XML文档。
<!DOCTYPE authors [
<!ELEMENT authors (author+)>
<!ELEMENT author (name,papers)>
<!ATTLIST author key ID #REQUIED >
<!ELEMENT name (#PCDATA)>
<!ELEMENT papers (paper+)>
<!ELEMENT paper (title,year,proceeding,authors?,page?)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT year (#PCDATA)>
<!ELEMENT proceeding (#PCDATA)>
<!ELEMENT page (#PCDATA)>
<!ELEMENT authors (author+)>
<!ELEMENT author (name)>
<!ELEMENT name (#PCDATA)>
]>
出于惯性,选择用java;为了方便调试和操作,没有选用现有的htmlparser之类的工具,而是采用正则表达式来匹配html源文件来提取作者的各种信息,然后用jdom生成符合DTD格式的XML文件。下面是几个tip:
(1)正则表达式
做这个工作最大的体会就是正则表达式这个看似简单的工具,功能还是很强大的。在提取信息的过程中,由于文章的标题,甚至是学者的名字中有可能包含匹配信息所依赖的标志符号。这样就会导致得到的不是想要的信息,甚至有时候会想是不是正则表达式的描述能力有限,没办法将两种情况区分开。但是,事实上,正则表达式的描述能力还是非常强悍的,只要将正则表达式写得复杂些,总能将想要的和不想要的信息区分开。正则语言表达能力强的理论依据是其与NFA(非确定性有限自动机一一对应)blablabla...
- 正则表达式匹配换行的时候,要使用选项DOTALL、MULTILINE之类的。具体地如何匹配一个换行要自己实验摸索,可以试试$\r\n^匹配一行结束到新行开始,也可以用[^.]+(.表示出新行之外的任意字符,这样正好可以匹配一行结束到一行开始)。
- 正则表达式匹配不回滚:正则表达式匹配的时候,匹配到一个内容,就从匹配内容结束字符的下一个字符开始寻找下一个匹配,而不是从匹配内容开始的下一个字符开始寻找下一个功能。简单的说,用aa去匹配aaaa,之后输出两个匹配,而不是三个。
int i=0; Pattern pt=null; Matcher mc=null; String str="aaaa"; String reg="aa"; pt = Pattern.compile(reg); mc = pt.matcher(str); while (mc.find()) { ++i; System.out.println(i+": "+mc.group(0)); } 输出: 1: aa 2: aa
- 正则表达式符号“|”的优先级比较低,(AB)C|CDE相当于((AB)C)|(CDE)。
(2)JVM内存相关
java不像C/C++,没有提供显示的动态分配内存的方法。所有的GC(垃圾回收机制)由jvm来实现。Java虚拟机默认分配64M内存,如果你的应用比较大,超出64M内存,Java虚拟机就会抛出outOfMemoryError,并停止运行。不过可以在eclipse中设置和jvm内存分配相关的参数:Window->Preference->Java->Installed JREs->选中要修改的一行,点Edit,在Default JVM Arguments中添加参数:-Xmx256M (也可以添加其他参数如-Xms128M -XX:PermSize=64M -XX:MaxPermSize=128M)。各参数意义如下:
JVM主要管理两种类型的内存:堆和非堆。堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。在JVM中堆之外的内存称为非堆内存(Non-heap memory)。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所有方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
- 堆内存分配
- 非堆内存分配
JVM的参数设置不能超过JVM内存的最大限制
因此,对以上参数进行设置时必须注意以下两点,否则可能导致程序无法启动: 参数中-Xms的值不能大于-Xmx,或者-XX:PermSize的值不能大于-XX:MaxPermSize;-Xmx的值和-XX:MaxPermSize的总和不能超过JVM内存的最大限制。(首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。)(3)将文件转化为大字符串
用正则表达式把HTML文件内容当做大字符串匹配,用下面的函数可以将一个文件转换为字符串。
//放在一个类的内部作为静态方法实现的
//将文件内容转为一个长字符串
public static String getContent(String fileName) throws Exception {
InputStream in = new FileInputStream(fileName);
byte[] aa = new byte[in.available()];
in.read(aa);
return new String(aa);
}
参考资料:
JVM内存相关:http://www.cnblogs.com/yyyyy5101/articles/1898737.html
文章浅显,欢迎交流。