




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Java正则表达式入门 + HTMLParser使用详解,一、 Java正则表达式入门 众所周知,在程序开发中,难免会遇到需要匹配、查找、替换、判断字符串的情况发生,而这些情况有时又比较复杂,如果用纯编码方式解决,往往会浪费程序员的时间及精力。 因此,学习及使用正则表达式,便成了解决这一矛盾的主要手段。 大家都知道,正则表达式是一种可以用于模式匹配和替换的规范,一个正则表达式就是由普通的字符(例如字符a到z)以及特殊字符(元字符)组成的文字模式,它 用以描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 自从jdk1.4推出java.
2、util.regex包,就为我们提供了很好的JAVA正则表达式应用平台。,说明,转义符,a,f,响铃符 = x07,换页符 = x0C,换页符,n,响铃符 = x07,换行 (u000A),r,回车符 = x0D,回车 (u000D),t,制表符 = x09,间隔 (u0009),v,垂直制表符 = x0B,e,ESC 符 = x1B, Escape,x20,使用两位十六进制表示形式,可与该编号的字符匹配,u002B,使用四位十六进制表示形式,可与该编号的字符匹配,x20A060,使用任意位十六进制表示形式,可与该编号的字符匹配,说明,字符,$,匹配输入字符串的开始位置。要匹配 字符本身,请使
3、用 ,匹配输入字符串的结尾位置。要匹配 “$” 字符本身,请使用 “$”,( ),标记一个子表达式的开始和结束位置。要匹配小括号,请使用 ( 和 ), ,用来自定义能够匹配 多种字符 的表达式。要匹配中括号,请使用 和 , ,修饰匹配次数的符号。要匹配大括号,请使用 和 ,.,匹配除了换行符(n)以外的任意一个字符。要匹配小数点本身,请使用 .,?,修饰匹配次数为 0 次或 1 次。要匹配 ? 字符本身,请使用 ?,+,修饰匹配次数为至少 1 次。要匹配 + 字符本身,请使用 +,*,修饰匹配次数为 0 次或任意次。要匹配 * 字符本身,请使用*,|,左右两边表达式之间 或 关系。匹配 | 本
4、身,请使用 |,说明,字符集合,.,w,小数点可以匹配除了换行符(n)以外的任意一个字符,可以匹配任何一个字母或者数字或者下划线,单独字符 a-zA-Z_0-9,W,W大写,可以匹配任何一个字母或者数字或者下划线以外的字符,非单独字符 a-zA-Z_0-9,s,可以匹配空格、制表符、换页符等空白字符的其中任意一个,空白符号 tnx0Bfr,S,S大写,可以匹配任何一个空白字符以外的字符,非空白符号tnx0Bfr,d,可以匹配任何一个 09 数字字符,数字 等价于0-9,D,D大写,可以匹配任何一个非数字字符,非数字 等价于0-9,字符集合 可以匹配 “多个字符” 其中任意一个字符的正则表达式。
5、虽然是 “多个字符”,但每次只能匹配其中一个。DEELX 正则表达式中标准的字符集合有:,说明,限定符,n,m, n,表达式固定重复n次,比如:w2 相当于 ww,表达式尽可能重复n次,至少重复m次:ba1,3可以匹配 ba或baa或baaa,m, ,表达式尽可能的多匹配,至少重复m次:“wd2,”可以匹配a12,x456.,?,表达式尽可能匹配1次,也可以不匹配,相当于 0, 1,+,表达式尽可能的多匹配,至少匹配1次,相当于 1, ,*,表达式尽可能的多匹配,最少可以不匹配,相当于 0, ,匹配次数限定符 使被修饰的表达式可多次重复匹配的修饰符。可使被修饰的表达式重复固定次数,也可以限定一
6、定的重复匹配的次数范围。在限定符之后的表达式能够匹配成功的情况下,不定次数的限定符总是尽可能的多匹配。如果之后的表达式匹配失败,限定符可适当“让出”能够匹配的字符,以使整个表达式匹配成功。这种模式就叫“贪婪模式”。,说明,限定符,m, n?,m, ?,表达式尽量只匹配m次,最多重复n次。,表达式尽量只匹配m次,最多可以匹配任意次。,?,表达式尽量不匹配,最多匹配1次,相当于 0, 1?,+?,表达式尽量只匹配1次,最多可匹配任意次,相当于 1, ?,*?,表达式尽量不匹配,最多可匹配任意次,相当于 0, ?,“勉强模式”限定符: 在限定符之后添加问号(?),则使限定符成为“勉强模式”。勉强模式
7、的限定符,总是尽可能少的匹配。如果之后的表达式匹配失败,勉强模式也可以尽可能少的再匹配一些,以使整个表达式匹配成功。,说明,限定符,m, n+,m, +,表达式尽可能重复n次,至少重复m次。,表达式尽可能的多匹配,至少重复m次。,?+,表达式尽可能匹配1次,也可以不匹配,相当于 0, 1+,+,表达式尽可能的多匹配,至少匹配1次,相当于 1, +,*+,表达式尽可能的多匹配,最少可以不匹配,相当于 0, +,“占有模式”限定符: 在限定符之后添加加号(+),则使限定符成为“占有模式”。占有模式的限定符,总是尽可能多的匹配。与“贪婪模式”不同的是,即使之后的表达式匹配失败,“占有模式”也不会“让
8、出”自己能够匹配的字符。,转义字符 Q.E 使用 Q 开始,E 结束,可使中间的标点符号失去特殊意义,将中间的字符作为普通字符。 例如: Q(a+b)*3E 可匹配文本 “(a+b)*3”。,因为正则表达式是一个很庞杂的体系,所以我仅例举些入门的概念,更多的请参阅相关书籍及自行摸索。,b 一个单词的边界B 一个非单词的边界G 前一个匹配的结束 为限制开头java 条件限制为以Java为开头字符$为限制结尾java$ 条件限制为以java为结尾字符. 条件限制除n以外任意一个单独字符java. 条件限制为java后除换行外任意两个字符 加入特定限制条件a-z 条件限制在小写a to z范围中一个
9、字符A-Z 条件限制在大写A to Z范围中一个字符a-zA-Z 条件限制在小写a to z或大写A to Z范围中一个字符,0-9 条件限制在小写0 to 9范围中一个字符0-9a-z 条件限制在小写0 to 9或a to z范围中一个字符0-9a-z 条件限制在小写0 to 9或a to z范围中一个字符(交集) 中加入后加再次限制条件a-z 条件限制在非小写a to z范围中一个字符A-Z 条件限制在非大写A to Z范围中一个字符a-zA-Z 条件限制在非小写a to z或大写A to Z范围中一个字符0-9 条件限制在非小写0 to 9范围中一个字符0-9a-z 条件限制在非小写0
10、to 9或a to z范围中一个字符0-9a-z 条件限制在非小写0 to 9或a to z范围中一个字符(交集)在 限制条件为特定字符出现0次以上时,可以使用*J* 0个以上J.* 0个以上任意字符,J.*D J与D之间0个以上任意字符 在限制条件为特定字符出现1次以上时,可以使用+J+ 1个以上J.+ 1个以上任意字符J.+D J与D之间1个以上任意字符 在限制条件为特定字符出现有0或1次以上时,可以使用?JA? J或者JA出现 限制为连续出现指定次数字符aJ2 JJJ3 JJJ 文字a个以上,并且a,J3, JJJ,JJJJ,JJJJJ,?(3次以上J并存),文字个以上,b个以下a,bJ
11、3,5 JJJ或JJJJ或JJJJJ两者取一|J|A J或AJava|Hello Java或Hello ()中规定一个组合类型比如,我查询index中间的数据,可写作+href=?(*)?*(.+?)在使用Ppile函数时,可以加入控制正则表达式的匹配行为的参数:Pattern Ppile(String regex, int flag),flag的取值范围如下: Pattern.CANON_EQ 当且仅当两个字符的正规分解(canonical decomposition)都完全相同的情况下,才认定匹配。比如用了这个标志之后,表达式au030A会匹配?。默认情况下,不考虑规 范相等性(canon
12、ical equivalence)。 Pattern.CASE_INSENSITIVE(?i) 默认情况下,大小写不明感的匹配只适用于US-ASCII字符集。这个标志能让表达式忽略大小写进行匹配。要想对Unicode字符进行大小不明感的匹 配,只要将UNICODE_CASE与这个标志合起来就行了。 Pattern.COMMENTS(?x) 在这种模式下,匹配时会忽略(正则表达式里的)空格字符,(译者注:不是指表达式里的s,而是指表达式里的空格,tab,回车之类)。注释从#开始,一直到这行结束。可以通过嵌入式的标志来启用Unix行模式。 Pattern.DOTALL(?s) 在这种模式下,表达式
13、.可以匹配任意字符,包括表示一行的结束符。默认情况下,表达式.不匹配行的结束符。Pattern.MULTILINE (?m) 在这种模式下,和$分别匹配一行的开始和结束。此外,仍然匹配字符串的开始,$也匹配字符串的结束。默认情况下,这两个表达式仅仅匹配字符串的开始和结束。Pattern.UNICODE_CASE (?u) 在这个模式下,如果你还启用了CASE_INSENSITIVE,2020年7月31日星期五12时28分45秒,标志,那么它会对Unicode字符进行大小写不明感的匹配。默认情况下,大小写不敏感的匹配只适用于US-ASCII字符集。 Pattern.UNIX_LINES(?d)
14、在这个模式下,只有n才被认作一行的中止,并且与.,以及$进行匹配。 抛开空泛的概念,下面写出几个简单的Java正则用例:比如,在字符串包含验证时/查找以Java开头,任意结尾的字符串Pattern pattern = Ppile(Java.*);Matcher matcher = pattern.matcher(Java不是人);boolean b= matcher.matches(); /当条件满足时,将返回true,否则返回falseSystem.out.println(b);,以多条件分割字符串时Pattern pattern = Ppile(, |+);String strs = pa
15、ttern.split(Java Hello World Java,Hello,World|Sun);for (int i=0;istrs.length;i+) System.out.println(strsi); 文字替换(首次出现字符)Pattern pattern = Ppile(正则表达式);Matcher matcher = pattern.matcher(正则表达式 Hello World,正则表达式 Hello World);/替换第一个符合正则的数据System.out.println(matcher.replaceFirst(Java);,文字替换(全部)Pattern pa
16、ttern = Ppile(正则表达式);Matcher matcher = pattern.matcher(正则表达式 Hello World,正则表达式 Hello World);/替换第一个符合正则的数据System.out.println(matcher.replaceAll(Java); 文字替换(置换字符)Pattern pattern = Ppile(“正则表达式”);Matcher matcher = pattern.matcher(“正则表达式 Hello World,正则表达式 Hello World ”);StringBuffer sbr = new StringBuff
17、er();while (matcher.find() matcher.appendReplacement(sbr, “Java”);,matcher.appendTail(sbr);System.out.println(sbr.toString(); 验证是否为邮箱地址String email=“w.-+(w-+.)+w-+”;String str=”;Pattern pattern = Ppile(email,Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(str);System.out.println(matcher.
18、matches(); 比较严格的: email=(0-9a-zA-Z(-.w*0-9a-zA-Z)*(0-9a-zA-Z)+(-w*0-9a-zA-Z)*.)+a-zA-Z2,9)$ 去除html标记 Pattern pattern = Ppile(, Pattern.DOTALL);,Matcher matcher = pattern.matcher(主页);String string = matcher.replaceAll();System.out.println(string); 查找html中对应条件字符串Pattern pattern = Ppile(href=(.+?);Matc
19、her matcher = pattern.matcher(主页);if(matcher.find()System.out.println(matcher.group(1); 截取http:/地址/截取urlPattern pattern = Ppile(http:/|https:/)1w.-/:+);,Matcher matcher = pattern.matcher(dsdsdsfdf); StringBuffer buffer = new StringBuffer();while(matcher.find() buffer.append(matcher.group(); buffer.a
20、ppend(rn); System.out.println(buffer.toString(); 替换指定中文字String str = Java目前的发展史是由0年-1年;String object=new String0,1995,new String1,2007;,System.out.println(replace(str,object); public static String replace(final String sourceString,Object object) String temp=sourceString; for(int i=0;iobject.length;i
21、+) String result=(String)objecti; Pattern pattern = Ppile(result0); Matcher matcher = pattern.matcher(temp); temp=matcher.replaceAll(result1); return temp;,读取页面链接和内容: public String newsListRegExp = +href=?( *)?*(.+?) ; newsListRegExp =+hrefs*=*s*(s|+)*(; public void getLinks(String content) java.uti
22、l.regex.Pattern pattern=java.util.regex.Ppile(newsListRegExp, java.util.regex.Pattern.CASE_INSENSITIVE); java.util.regex.Matcher matcher=pattern.matcher(content); while(matcher.find() String link=matcher.group(1); String text=matcher.group(2); System.out.println(link+text); ,Java正则的功用还有很多,事实上只要是字符处理
23、,就没有正则做不到的事情存在。 (当然,正则解释时较耗时间就是了!),二、 HTMLParser使用详解,HTMLParser使用详解(1)- 初始化Parser,在研究搜索引擎的开发中,对于HTML网页的处理是核心的一个环节。网上有很多开源的代码,对于Java来说,HTMLParser是比较著名并且得到广泛应用的一个。 HTMLParser的主页是 ,最后的更新是2006年9月的1.6版。不过没关系,HTML的内容已经很久没有大的变化了,HTMLParser处理起来基本没有任何问题。,HTMLParser的核心模块是org.htmlparser.Parser类,这个类实际完成了对于HTML页
24、面的分析工作。这个类有下面几个构造函 数: public Parser ();public Parser (Lexer lexer, ParserFeedback fb); public Parser (URLConnection connection, ParserFeedback fb) throws ParserException; public Parser (String resource, ParserFeedback feedback) throws ParserException; public Parser (String resource) throws ParserExc
25、eption;public Parser (Lexer lexer);public Parser (URLConnection connection) throws ParserException;和一个静态类 public static Parser createParser (String html, String charset);,对于大多数使用者来说,使用最多的是通过一个URLConnection或者一个保存有网页内容的字符串来初始化Parser,或者使用静态函数来生成一个Parser对象。 ParserFeedback的代码很简单,是针对调试和跟踪分析过程的,一般不需要改变。而使用
26、Lexer则是一个相对比较高级的话题,放到以后再讨论吧。 这里比较有趣的一点是,如果需要设置页面的编码方式的话,不使用Lexer就只有静态函数一个方法了。 对于大多数中文页面来说,好像这是应该用得比较多的一个方法。,HTMLParser使用详解(2)- Node内容,HTMLParser将解析过的信息保存为一个树的结构。Node是信息保存的数据类型基础。 请看Node的定义:public interface Node extends Cloneable; Node中包含的方法有几类: 对于树型结构进行遍历的函数,这些函数最容易理解: Node getParent ():取得父节点NodeLis
27、t getChildren ():取得子节点的列表,Node getFirstChild ():取得第一个子节点Node getLastChild ():取得最后一个子节点 Node getPreviousSibling ():取得前一个兄弟(不好意思,英文是兄弟姐妹,直译太麻烦而且不符合习惯,对不起女同胞了)Node getNextSibling ():取得下一个兄弟节点 取得Node内容的函数: String getText ():取得文本String toPlainTextString():取得纯文本信息。 String toHtml () :取得HTML信息(原始HTML)String
28、 toHtml (boolean verbatim):取得HTML信息(原始HTML)String toString ():取得字符串信息(原始HTML)Page getPage ():取得这个Node对应的Page对象,int getStartPosition ():取得这个Node在HTML页面中的起始位置int getEndPosition ():取得这个Node在HTML页面中的结束位置用于Filter过滤的函数: void collectInto (NodeList list, NodeFilter filter):基于filter的条件对于这个节点进行过滤,符合条件的节点放到lis
29、t中。 用于Visitor遍历的函数: void accept (NodeVisitor visitor):对这个Node应用visitor用于修改内容的函数,这类用得比较少: void setPage (Page page):设置这个Node对应的Page对象void setText (String text):设置文本void setChildren (NodeList children):设置子节点列表,其他函数: void doSemanticAction ():执行这个Node对应的操作(只有少数Tag有对应的操作)Object clone ():接口Clone的抽象函数。 主要注意
30、一下,getText,toPlainTextString ,toHtml 区别 String a=猫扑hi来点不一样 ; Parser p=Parser.createParser(a, UTF-8); try for(NodeIterator it= p.elements();it.hasMoreNodes();) Node node=it.nextNode() ; System.out.println(node.getText()+$+node.toPlainTextString()+$+node.toHtml(); catch (ParserException e) / TODO Auto
31、-generated catch block e.printStackTrace(); 输出: div id=hi$猫扑hi$猫扑hi a class=link href= $来点不一样$来点不一样,下面是用于测试的HTML文件: 白泽居- 白泽居-白泽居- 白泽居-,toPlainTextString是把用户可以看到的内容都包含了。有趣的有两点,一是标签中的Title内容是在plainText中的,可能在标题中可见的也算可见吧。 另外就是象前面说的,HTML内容中的换行符什么的,也都成了plainText,这个逻辑上好像有点问题。另外可能大家发现toHtml,toHtml(true)和toH
32、tml(false)的结果没什么区别。实际也是这样的,如果,跟踪HTMLParser的代码就可以发现,Node的子类是AbstractNode,其中实现了toHtml()的代码,直接调用toHtml(false),而AbstractNode的三个子类RemarkNode,TagNode和TextNode中,toHtml(boolean verbatim)的实现中,都没有处理verbatim参数,所以三个函数的结果是一模一样的。 如果你不需要实现你自己的什么特殊处理,简单使用toHtml就可以了。,HTML的Node类继承关系如下图这个是从别的文章Copy的):,AbstractNodes是No
33、de的直接子类,也是一个抽象类。它的三个直接子类实现是RemarkNode,用于保存注释。在输出结果的toString部分中可以看到有一个Rem (3456,2,3566,13): 这是注释,就是一个RemarkNode。TextNode也很简单,就是用户可见的文字信息。 TagNode是最复杂的,包含了HTML语言中的所有标签,而且可以扩展(扩展 HTMLParser 对自定义标签的处理能力 )。TagNode包含两类,一类是简单的Tag,实际就是不能包含其他Tag的标签,只能做叶子节点。另一类是CompositeTag,就是可以包含其他Tag,是分支节点。,遍历了网页的内容以后,以树(森林
34、)结构保存了结果。HTMLParser访问结果内容的方法有两种。使用Filter和使用Visitor。 (一)Filter类 顾名思义,Filter就是对于结果进行过滤,取得需要的内容。HTMLParser在org.htmlparser.filters包之内一共定义了16个不同的Filter,也可以分为几类。,HTMLParser使用详解(3)- 通过Filter访问内容,判断类Filter: TagNameFilterHasAttributeFilterHasChildFilterHasParentFilterHasSiblingFilterIsEqualFilter 逻辑运算Filter:
35、 AndFilterNotFilterOrFilterXorFilter,其他Filter: NodeClassFilterStringFilterLinkStringFilterLinkRegexFilterRegexFilterCssSelectorNodeFilter 所有的Filter类都实现了org.htmlparser.NodeFilter接口。这个接口只有一个主要函数:boolean accept (Node node); 各个子类分别实现这个函数,用于判断输入的Node是否符合这个Filter的过滤条件,如果符合,返回true,否则返回false。,(二)判断类Filter H
36、TMLParser使用入门(2)- Node内容 ,自己添加import部分)public static void main(String args) try Parser parser = new Parser( (HttpURLConnection) (new URL(:8080/HTMLParserTester.html).openConnection() ); / 这里是控制测试的部分,后面的例子修改的就是这个地方。 NodeFilter filter = new TagNameFilter (DIV); NodeList nodes = parser.e
37、xtractAllNodesThatMatch(filter);,if(nodes!=null) for (int i = 0; i nodes.size(); i+) Node textnode = (Node) nodes.elementAt(i); message(getText:+textnode.getText(); message(=); catch( Exception e ) e.printStackTrace(); 输出结果:getText:div id=top_main,=getText:div id=logoindex=可以看出文件中两个Div节点都被取出了。下面可以针对
38、这两个DIV节点进行操作 2.2 HasChildFilter 下面让我们看看HasChildFilter。刚刚看到这个Filter的时候,我想当然地认为这个Filter返回的是有Child的Tag。直接初始化了一个NodeFilter filter = new HasChildFilter();,结果调用NodeList nodes = parser.extractAllNodesThatMatch(filter);的时候HasChildFilter内部直接发生NullPointerException。读了一下HasChildFilter的代码,才发现,实际HasChildFilter是返回
39、有符合条件的子节点的节点,需要另外一个Filter作为过滤子节点的参数。 缺省的构造函数虽然可以初始化,但是由于子节点的Filter是null,所以使用的时候发生了Exception。 从这点来看,HTMLParser的代码还有很多可以优化的的地方。呵呵。,修改代码: NodeFilter innerFilter = new TagNameFilter (DIV);NodeFilter filter = new HasChildFilter(innerFilter);NodeList nodes = parser.extractAllNodesThatMatch(filter);输出结果: g
40、etText:body = getText:div id=top_main= 可以看到,输出的是两个有DIV子Tag的Tag节点。(body有子节点DIV top_main,top_main有子节点logoindex。,注意HasChildFilter还有一个构造函数:public HasChildFilter (NodeFilter filter, boolean recursive) 如果recursive是false,则只对第一级子节点进行过滤。比如前面的例子,body和top_main都是在第一级的子节点里就有DIV节点,所以匹配上了。如果我们用下面的方法调用:NodeFilter f
41、ilter = new HasChildFilter( innerFilter, true ); 输出结果: getText:html xmlns=/1999/xhtml=getText:body = getText:div id=top_main=,可以看到输出结果中多了一个html xmlns=/1999/xhtml,这个是整个HTML页面的节点(根节点),虽然这个节点下直接没有DIV节点,但是它的子节点body下面有DIV节点,所以它也被匹配上了。 2.3 HasAttributeFilter HasAttributeFil
42、ter有3个构造函数:public HasAttributeFilter ();public HasAttributeFilter (String attribute);public HasAttributeFilter (String attribute, String value);这个Filter可以匹配出包含制定名字的属性,或者制定属性为指定值的节点。还是用例子说明比较容易。,调用方法1: NodeFilter filter = new HasAttributeFilter();NodeList nodes = parser.extractAllNodesThatMatch(filte
43、r); 输出结果: 什么也没有输出。调用方法2: NodeFilter filter = new HasAttributeFilter( id );NodeList nodes = parser.extractAllNodesThatMatch(filter);,输出结果: getText:div id=top_main=getText:div id=logoindex= 调用方法3: NodeFilter filter = new HasAttributeFilter( id, logoindex );NodeList nodes = parser.extractAllNodesThatMa
44、tch(filter);输出结果: getText:div id=logoindex= 很简单吧。呵呵,2.4 其他判断列Filter HasParentFilter和HasSiblingFilter的功能与HasChildFilter类似,大家自己试一下就应该了解了。IsEqualFilter的构造函数参数是一个Node:public IsEqualFilter (Node node) mNode = node; accept函数也很简单:public boolean accept (Node node) return (mNode = node);不需要过多说明了。,(三)逻辑运算Filt
45、er (四)其他Filter: HTMLParser使用入门(2)- Node内容 中我们已经了解了Node的不同类型,这个Filter就可以针对类型进行过滤。测试代码: NodeFilter filter = new NodeClassFilter(RemarkNode.class); NodeList nodes = parser.extractAllNodesThatMatch(filter); 输出结果: getText:这是注释= 可以看到只有RemarkNode(注释)被输出了。,4.2 StringFilter 这个Filter用于过滤显示字符串中包含制定内容的Tag。注意是可显
46、示的字符串,不可显示的字符串中的内容(例如注释,链接等等)不会被显示。 修改一下例子代码: 白泽居-title-, 白泽居-字符串1- 白泽居-链接文本- 白泽居-字符串2-,测试代码: NodeFilter filter = new StringFilter(); NodeList nodes = parser.extractAllNodesThatMatch(filter); 输出结果: getText:白泽居-title-= getText: 白泽居-字符串1-=getText:白泽居-链接文本-=,getText: 白泽居-字符串2-= 可以看到包含title,两个内容字符串和链接的文
47、本字符串的Tag都被输出了,但是注释和链接Tag本身没有输出。 4.3 LinkStringFilter 这个Filter用于判断链接中是否包含某个特定的字符串,可以用来过滤出指向某个特定网站的链接。测试代码: NodeFilter filter = new LinkStringFilter(); NodeList nodes = parser.extractAllNodesThatMatch(filter);,输出结果: getText:a href= 4.4 其他几个Filter 其他几个Filter也是根据字符串对不同的域进行判断,与前面这些的区别主要就是支持正则表达式。这个不在本文的讨
48、论范围以内,大家可以自己实验一下。 前面介绍的都是简单的Filter,只能针对某种单一类型的条件进行过滤。HTMLParser支持对于简单类型的Filter进行组合,从而实现复杂的条件。原理和一般编程语言的逻辑运算是一样的。,3.1 AndFilter AndFilter可以把两种Filter进行组合,只有同时满足条件的Node才会被过滤。 测试代码: NodeFilter filterID = new HasAttributeFilter( “id” );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filte
49、r = new AndFilter(filterID, filterChild);输出结果:getText:div id=“logoindex”=,3.2 OrFilter 把前面的AndFilter换成OrFilter测试代码: NodeFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new OrFilter(filterID, filterChild); 输出结果: getText:div id=to
50、p_main= getText:div id=logoindex=,3.3 NotFilter 把前面的AndFilter换成NotFilter测试代码: NodeFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new NotFilter(new OrFilter(filterID, filterChild); 输出结果: getText:!DOCTYPE html PUBLIC -/W3C/DTD XH
51、TML 1.0 Transitional/EN /TR/xhtml1/DTD/xhtml1-transitional.dtd=getText:,=getText:head=getText:meta http-equiv=Content-Type content=text/html; charset=gb2312=getText:title =getText:白泽居-=getText:/title= getText:/head,=getText:=getText:html xmlns=/1999/xhtml=getText: =ge
52、tText:body =getText:=getText:,=getText: = getText:这是注释= getText: 白泽居- =getText:a href=getText:白泽居-=getText:/a,=getText: =getText:/div=getText: 白泽居- = getText:/div= getText:,= getText:/body= getText: =getText:/html=getText:=除了前面3.2中输出的几个Tag,其余的Tag都在这里了。,3.4 XorFilter 把前面的AndFilter换成NotFilter测试代码: Nod
53、eFilter filterID = new HasAttributeFilter( id );NodeFilter filterChild = new HasChildFilter(filterA);NodeFilter filter = new XorFilter(filterID, filterChild); 输出结果: getText:div id=top_main= 4.1 NodeClassFilter 这个Filter用于判断节点类型是否是某个特定的Node类型。在,2.1 TagNameFilter TabNameFilter是最容易理解的一个Filter,根据Tag的名字进行
54、过滤。 下面是用于测试的HTML文件: 白泽居-, 白泽居-白泽居- 白泽居- ,HTMLParser遍历了网页的内容以后,以树(森林)结构保存了结果。HTMLParser访问结果内容的方法有两种。 使用Filter和使用Visitor。 下面介绍使用Visitor访问内容的方法。 4.1 NodeVisitor 从简单方面的理解,Filter是根据某种条件过滤取出需要的Node再进行处理。Visitor则是遍历,HTMLParser使用详解(4)- 通过Visitor访问,内容树的每一个节点,对于符合条件的节点进行处理。实际的结果异曲同工,两种不同的方法可以达到相同的结果。下面是一个最常见的NodeVisitro的例子。 测试代码: public static void main(String args) try Parser parser = new Parser( (HttpURLConnection) (new URL(:8080/HTMLParserTester.html).openConnection() );,NodeVisitor visitor = new NodeVisitor( false, false ) public void visitTag(Tag tag) message(This is Tag:+ta
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 城市道路改造工程合同书
- 原料供应合同
- 连锁餐厅与旅行社定点合作合同
- 水产养殖基地租赁合同范本
- 粘土盒美术课件
- 植物考试模拟题与参考答案
- 租赁车位合同简易版
- 工商局标准股份转让合同范本
- 职业生涯教育
- 跨国电子商务交易合作框架协议
- 《保护地球爱护家园》课件
- 雾化吸入疗法合理用药专家共识(2024版)解读
- 2024年度产学研合作与科研奖励协议3篇
- 电力工程线路交叉跨越施工主要工序及特殊工序施工方法
- 【MOOC】软件度量及应用-中南大学 中国大学慕课MOOC答案
- 24秋国家开放大学《儿童发展问题的咨询与辅导》周测验参考答案
- 2025届江苏省苏州市重点中学高三第二次模拟考试英语试卷含解析
- JJF(京) 124-2024 智能电表电动自行车充电辨识模组校准规范
- DB65-T 4783-2024 冰川资源遥感调查技术规范
- 护士中级职称竞聘述职课件
- 2024年江苏省徐州市中考一模物理试题(含答案)
评论
0/150
提交评论