灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2029回复:0

java处理字符串搜索嵌套结构的方法

楼主#
更多 发布于:2012-09-08 09:35

在用java分析HTML文本时,如果要取出有嵌套结构的节点之间的内容,不能直接用正则表达式来处理,因为java所带的正则表达式不支持嵌套结构的描述,虽然Perl、.Net、php可以支持。这时可以先用正则表达式找出节点在字符串中的位置,然后对节点进行匹配处理,取出匹配节点之间的内容,实现对嵌套结构的处理。

例如要从

[html]
<pre name="code" class="java">data=<div><div>abcd<div></div><form><input type='button' value='submit'/></form></div></div><div>1234</div>
中取出<div></div>之间的内容,希望返回两个字符串
[html]
<pre name="code" class="java"><div>abcd<div></div><form><input type='button' value='submit'/></form></div><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,"<div>", "</div>") 返回含有两个元素的列表,元素分别为

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

需要注意的是如果节点含有正则表达式的元字符,需要在元字符前加转义符\\,源代码中第16,17行实现此功能。



喜欢0 评分0
游客

返回顶部