对整段内容进行匹配和替换

功能,在整段文本内容中,查找符合某些条件的内容,进行替换。需要注意的是,因为查找了替换是两个步骤,可能造成替换的内容并非查找的内容。

 

package com.shuwei.tools;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * 对一段文本中的某些字符进行处理后,再替换
 */
public class BigContentReplace {
	public static void main(String[] args) {
		/*
		long startTime = System.currentTimeMillis();
		String content = "1111aa2222<a href='aa'></a>3333bb444<action='bbbb'/>555ccc'ccc'";
		for(int i = 0; i < 1000000; i++){
			replace1(content);
		}
		long endTime = System.currentTimeMillis();
		System.out.println(endTime - startTime);
		
		startTime = System.currentTimeMillis();
		for(int i = 0; i < 1000000; i++){
			replace2(content);
		}
		endTime = System.currentTimeMillis();
		System.out.println(endTime - startTime);
		*/
		String content1 = "1111aa2222<a href='aa'></a>3333bb444<action='bbbb'/>555ccc'ccc'";
		content1 = replace1(content1);
		System.out.println(content1);
		String content2 = "1111aa2222<a href='aa'></a>3333bb444<action='bbbb'/>555ccc'ccc'";
		content2 = replace2(content2);
		System.out.println(content2);
	}
	
	/*
	 * 思路:先找出匹配组,然后对匹配项进行处理,最后对内容进行精确替换
	 * 优点:便于理解
	 * 缺点:操作步骤较多
	 */
	public static String replace1(String content){
		//将单引号中的内容使用encode后的内容替换
		//如:需要将下面content中的页面链接后面根据链接的字符数n加上n个T
		
		//由于需要根据对需要替换的字符进行处理,不能使用直接的content.replaceAll(),因为需要获得匹配的部分
		Pattern p = Pattern.compile("((href=)|(action=))'.*?'");
		Matcher m = p.matcher(content);
		while(m.find()){
			String target = m.group();
			int start = target.indexOf('\'');
			int end = target.indexOf('\'', start + 1);
			String replacement = target.substring(0, start + 1) + encode(target.substring(start + 1, end)) + 
			target.substring(end);
			content = content.replace(target, replacement);
		}
		return content;
	}
	
	/**
	 * 思路:先获得每次匹配时候字符串的长度,由于从前往后替换,每次替换后在实际的字符串中的位置会变动
	 * 所以需要保存原始字符串的长度和当前匹配内容的开始位置,计算差。然后再使用长度进行替换
	 * 需要注意的是,每次匹配的内容距离实际字符串尾部的位置是不会变的
	 * @param content
	 * @return
	 */
	public static String replace2(String content){
		Pattern p = Pattern.compile("((href=)|(action=))'(.*?)'");
		Matcher m = p.matcher(content);
		int length = content.length();
		
		while(m.find()){
			String target = m.group(4);
			/**
			 * 这段代码会产生错位的问题--至于原因自己可以分析下 
			int start = m.start();
			int end = m.end();
			content = content.substring(0, start) + encode(target) + 
					content.substring(end);
			 */
			int dis = length - m.end();
			//当前字符串内容中的结束位置
			int currentEnd = content.length() - dis - 1;
			content = content.substring(0, currentEnd - target.length()) + 
					encode(target) + content.substring(currentEnd);
		}
		return content;
	}
	
	public static String encode(String str){
		StringBuilder sb = new StringBuilder(str);
		for(int i = 0; i < str.length(); i++){
			sb.append("T");
		}
		return sb.toString();
	}
}


replace1的思路相对比较容易理解,即匹配什么就对什么进行一次替换。

replace2采用拼接的做法,理解起来也不难,只是容易犯一个注释中的错误。

经测试,代码中的字符串替换100万次,使用replace1需要10秒钟,而使用replace2需要6秒钟,字符串内容多了性能差异应该更明显。所以尽量使用replace2方法。

使用StringBuilder对replace2进行优化

public static String replace2(String content){
		Pattern p = Pattern.compile("((href=)|(action=))'(.*?)'");
		Matcher m = p.matcher(content);
		StringBuilder sb = new StringBuilder(content);
		int length = content.length();
		
		while(m.find()){
			String target = m.group(4);
			/**
			 * 这段代码会产生错位的问题--至于原因自己可以分析下 
			int start = m.start();
			int end = m.end();
			content = content.substring(0, start) + encode(target) + 
					content.substring(end);
			 */
			int dis = length - m.end();
			//当前字符串内容中的结束位置
			int currentEnd = sb.length() - dis - 1;
			int currentStart = currentEnd - target.length();
			sb.delete(currentStart, currentEnd);
			sb.insert(currentStart, encode(target));
			/*
			sb.delete(0, currentEnd - target.length()) + 
					encode(target) + content.substring(currentEnd);
					*/
		}
		return sb.toString();
	}


在测试代码中,执行100万次replace2的时间仍然是6秒,可能因为测试数据的content比较短的原因。对于content比较大的时候性能应该会有提升。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值