现在的位置: 首页 > 综合 > 正文

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

2013年04月13日 ⁄ 综合 ⁄ 共 2253字 ⁄ 字号 评论关闭

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

例如要从

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

中取出<div></div>之间的内容,希望返回两个字符串

<div>abcd<div></div><form><input type='button' value='submit'/></form></div>
和1234。


源代码如下:

为了记录节点在字符串中的值和位置,先定义一个类,保存这些信息:

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;
	}
	
	
	
}

从字符串中获取节点之间内容的函数如下:

        /**
	 * 获取字符串之间的内容,如果包含嵌套,则返回最外层嵌套内容
	 * 
	 * @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>") 返回含有两个元素的列表,元素分别为

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

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




抱歉!评论已关闭.