功能,在整段文本内容中,查找符合某些条件的内容,进行替换。需要注意的是,因为查找了替换是两个步骤,可能造成替换的内容并非查找的内容。
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比较大的时候性能应该会有提升。