java處理字符串搜索嵌套結構的方法 – JAVA編程語言程序開發技術文章

在用java分析HTML文本時,如果要取出有嵌套結構的節點之間的內容,不能直接用正則表達式來處理,因為java所帶的正則表達式不支持嵌套結構的描述,雖然Perl、.Net、PHP可以支持。這時可以先用正則表達式找出節點在字符串中的位置,然後對節點進行匹配處理,取出匹配節點之間的內容,實現對嵌套結構的處理。
 
例如要從
 
[html]
<pre name="code" class="java">data=<p><p>abcd<p></p><form><input type='button' value='submit'/></form></p></p><p>1234</p> 
中取出<p></p>之間的內容,希望返回兩個字符串
[html]
<pre name="code" class="java"><p>abcd<p></p><form><input type='button' value='submit'/></form></p><pre name="code" class="html">和1234。 
 
 
源代碼如下:
 
為瞭記錄節點在字符串中的值和位置,先定義一個類,保存這些信息:
 
[java]
public class Tag { 
     
    public Tag(String value, int beginPos, int endPos) { 
        super(); 
        this.value = value; 
        this.beginPos = beginPos; 
        this.endPos = endPos; 
    } 
    private String value; 
    private int beginPos; 
    private int endPos; 
    public String getValue() { 
        return value; 
    } 
    public void setValue(String value) { 
        this.value = value; 
    } 
    public int getBeginPos() {  
        return beginPos; 
    } 
    public void setBeginPos(int beginPos) { 
        this.beginPos = beginPos; 
    } 
    public int getEndPos() { 
        return endPos; 
    } 
    public void setEndPos(int endPos) { 
        this.endPos = endPos; 
    } 
     
     
     

 
從字符串中獲取節點之間內容的函數如下:
[java]
       /**
 * 獲取字符串之間的內容,如果包含嵌套,則返回最外層嵌套內容
 * 
 * @param data      
 * @param stag      起始節點串
 * @param etag      結束節點串
 * @return
 */ 
public List<String> get(String data,String stag, String etag){ 
    // 存放起始節點,用於和結束節點匹配 
    Stack<Tag> work = new Stack<Tag>(); 
    // 保存所有起始和結束節點 
    List<Tag> allTags = new ArrayList<Tag>(); 
     
    // 在元字符前加轉義符 
    String nstag = stag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1"); 
    String netag = etag.replaceAll("([\\*\\.\\+\\(\\]\\[\\?\\{\\}\\^\\$\\|\\\\])", "\\\\$1"); 
     
    String reg = "((?:"+nstag+")|(?:"+netag+"))"; 
     
    Pattern p = Pattern.compile(reg, Pattern.CASE_INSENSITIVE|Pattern.MULTILINE); 
     
    Matcher m = p.matcher(data); 
     
    while(m.find()){ 
        Tag tag = new Tag(m.group(0),m.start(),m.end()); 
        allTags.add(tag); 
    } 
    // 保存開始結束節點之間的內容,不含節點 
    List<String> result = new ArrayList<String>(); 
     
    for(Tag t : allTags){ 
        if (stag.equalsIgnoreCase(t.getValue())){ 
            work.push(t); 
        }else if(etag.equalsIgnoreCase(t.getValue())){ 
            // 如果棧已空,則表示不匹配 
            if (work.empty()){ 
                throw new RuntimeException("pos "+t.getBeginPos()+" tag not match start tag."); 
            } 
            Tag otag = work.pop(); 
            // 如果棧為空,則匹配 
            if (work.empty()){ 
                String sub = data.substring(otag.getEndPos(), t.getBeginPos()); 
                result.add(sub); 
            } 
        } 
         
    } 
     
    // 如果此時棧不空,則有不匹配發生 
    if (!work.empty()){ 
        Tag t = work.pop(); 
        throw new RuntimeException("tag "+t.getValue()+ "not match."); 
    } 
     
    return result; 
     

 
函數返回節點之間內容串組成的列表。
例如 調用get(data,"<p>", "</p>") 返回含有兩個元素的列表,元素分別為
 
[html]
<p>abcd<p></p><form><input type='button' value='>'/></form></p>, 1234 
 
需要註意的是如果節點含有正則表達式的元字符,需要在元字符前加轉義符\\,源代碼中第16,17行實現此功能。

摘自 indexchen的專欄

發佈留言