qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

          Java處理字符串搜索嵌套結(jié)構(gòu)的方法

           在用Java分析HTML文本時(shí),如果要取出有嵌套結(jié)構(gòu)的節(jié)點(diǎn)之間的內(nèi)容,不能直接用正則表達(dá)式來處理,因?yàn)镴ava所帶的正則表達(dá)式不支持嵌套結(jié)構(gòu)的描述,雖然Perl、.Net、PHP可以支持。這時(shí)可以先用正則表達(dá)式找出節(jié)點(diǎn)在字符串中的位置,然后對(duì)節(jié)點(diǎn)進(jìn)行匹配處理,取出匹配節(jié)點(diǎn)之間的內(nèi)容,實(shí)現(xiàn)對(duì)嵌套結(jié)構(gòu)的處理。

            例如要從

          1. <pre name="code" class="java">data=<div><div>abcd<div></div><form>
          2. <input type='button' value='submit'/></form></div></div><div>1234</div>

            中取出<div></div>之間的內(nèi)容,希望返回兩個(gè)字符串

          1. <pre name="code" class="java"><div>abcd<div></div><form>
          2. <input type='button' value='submit'/></form></div><pre name="code" class="html">和1234

            源代碼如下:

            為了記錄節(jié)點(diǎn)在字符串中的值和位置,先定義一個(gè)類,保存這些信息:

          1. public class Tag {  
          2.       
          3.     public Tag(String value, int beginPos, int endPos) {  
          4.         super();  
          5.         this.value = value;  
          6.         this.beginPos = beginPos;  
          7.         this.endPos = endPos;  
          8.     }  
          9.     private String value;  
          10.     private int beginPos;  
          11.     private int endPos;  
          12.     public String getValue() {  
          13.         return value;  
          14.     }  
          15.     public void setValue(String value) {  
          16.         this.value = value;  
          17.     }  
          18.     public int getBeginPos() {  
          19.         return beginPos;  
          20.     }  
          21.     public void setBeginPos(int beginPos) {  
          22.         this.beginPos = beginPos;  
          23.     }  
          24.     public int getEndPos() {  
          25.         return endPos;  
          26.     }  
          27.     public void setEndPos(int endPos) {  
          28.         this.endPos = endPos;  
          29.     }  
          30.       
          31. }

            從字符串中獲取節(jié)點(diǎn)之間內(nèi)容的函數(shù)如下:

          1.        /** 
          2.  * 獲取字符串之間的內(nèi)容,如果包含嵌套,則返回最外層嵌套內(nèi)容 
          3.  *  
          4.  * @param data       
          5.  * @param stag      起始節(jié)點(diǎn)串 
          6.  * @param etag      結(jié)束節(jié)點(diǎn)串 
          7.  * @return 
          8.  */ 
          9. public List<String> get(String data,String stag, String etag){  
          10.     // 存放起始節(jié)點(diǎn),用于和結(jié)束節(jié)點(diǎn)匹配 
          11.     Stack<Tag> work = new Stack<Tag>();  
          12.     // 保存所有起始和結(jié)束節(jié)點(diǎn) 
          13.     List<Tag> allTags = new ArrayList<Tag>();  
          14.       
          15.     // 在元字符前加轉(zhuǎn)義符 
          16.     String nstag = stag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])""\\\\$1");  
          17.     String netag = etag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])""\\\\$1");  
          18.       
          19.     String reg = "((?:"+nstag+")|(?:"+netag+"))";  
          20.       
          21.     Pattern p = Pattern.compile(reg, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);  
          22.       
          23.     Matcher m = p.matcher(data);  
          24.       
          25.     while(m.find()){  
          26.         Tag tag = new Tag(m.group(0),m.start(),m.end());  
          27.         allTags.add(tag);  
          28.     }  
          29.     // 保存開始結(jié)束節(jié)點(diǎn)之間的內(nèi)容,不含節(jié)點(diǎn) 
          30.     List<String> result = new ArrayList<String>();  
          31.       
          32.     for(Tag t : allTags){  
          33.         if (stag.equalsIgnoreCase(t.getValue())){  
          34.             work.push(t);  
          35.         }else if(etag.equalsIgnoreCase(t.getValue())){  
          36.             // 如果棧已空,則表示不匹配 
          37.             if (work.empty()){  
          38.                 throw new RuntimeException("pos "+t.getBeginPos()+" tag not match start tag.");  
          39.             }  
          40.             Tag otag = work.pop();  
          41.             // 如果棧為空,則匹配 
          42.             if (work.empty()){  
          43.                 String sub = data.substring(otag.getEndPos(), t.getBeginPos());  
          44.                 result.add(sub);  
          45.             }  
          46.         }  
          47.           
          48.     }  
          49.       
          50.     // 如果此時(shí)棧不空,則有不匹配發(fā)生 
          51.     if (!work.empty()){  
          52.         Tag t = work.pop();  
          53.         throw new RuntimeException("tag "+t.getValue()+ "not match.");  
          54.     }  
          55.       
          56.     return result;  
          57.       
          58. }

            函數(shù)返回節(jié)點(diǎn)之間內(nèi)容串組成的列表。

            例如 調(diào)用 get(data,"<div>", "</div>") 返回含有兩個(gè)元素的列表,元素分別為

          <div>abcd<div></div><form><input type='button' value='>'/></form></div>, 1234

            需要注意的是如果節(jié)點(diǎn)含有正則表達(dá)式的元字符,需要在元字符前加轉(zhuǎn)義符\\,源代碼中第16,17行實(shí)現(xiàn)此功能。

          posted on 2012-02-07 15:21 順其自然EVO 閱讀(235) 評(píng)論(0)  編輯  收藏


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2012年2月>
          2930311234
          567891011
          12131415161718
          19202122232425
          26272829123
          45678910

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 鲁山县| 五大连池市| 岳阳县| 崇明县| 临邑县| 长春市| 大理市| 旅游| 锡林浩特市| 洛隆县| 娱乐| 兴和县| 寿阳县| 房山区| 拉萨市| 云阳县| 忻城县| 新乡县| 安福县| 正镶白旗| 荆门市| 凤阳县| 中卫市| 监利县| 阿尔山市| 盐边县| 沈阳市| 清新县| 乌拉特后旗| 察哈| 鱼台县| 环江| 长乐市| 双峰县| 龙川县| 黄梅县| 蓝山县| 邻水| 丹棱县| 凤山县| 云浮市|