我们的项目中需要获取Git的日志数据,用到git log命令进行日志的获取。Git没有像SVN那样,提供定义好的xml格式的日志文件。但是可以自己定义格式:git log --pretty=format:"your own format",然后我用自己写的xml标签加git提供的一些placeholder生成了类似于xml的日志文件。主要还是觉得xml文件比较方便解析。
然后发现这样生成的xml日志文件存在问题:日志的提交说明(message)是由用户填写的,那么用户就可能写入“&”“<”“>”这样的内容。众所周知xml里出现单独的这些字符是不合法的,该文件是不能被解析的。
在svn里,用户如果在提交说明里输入“&”“<”“>”,生成的xml日志文件会自动把它们转换成“&”“<”“>“。但是git内部并不知道我定义的格式是xml的,那么也就不会自动转换。所以,我生成的git日志文件后,需要把提交说明<msg></msg>标签里的“&”“<”“>”替换为对应的转义字符。
主要的思想是用java.lang.String中的replaceAll(String regex, String replacement)函数进行替换。
查了java.util.regex.Pattern
和java.util.regex.Matcher
两个类的文档。
java.util.regex.Pattern
组和捕获:
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C))) 2 \A 3 (B(C)) 4 (C)
组零始终代表整个表达式。
java.util.regex.Matcher
关于替换字符串:
替换字符串可能包含到以前匹配期间所捕获的子序列的引用:$g 每次出现时,都将被
group
(g) 的计算结果替换。$ 之后的第一个数始终被视为组引用的一部分。如果后续的数可以形成合法组引用,则将被合并到 g 中。只有数字 '0' 到 '9' 被视为组引用的可能组件。例如,如果第二个组匹配字符串 "foo",则传递替换字符串 "$2bar" 将导致 "foobar" 被添加到字符串缓冲区。
所以我用了括号和$g来进行替换:
public void chartReplace(){
String str2 = "<logentry revision='1'>" +
"<msg>In this comment, I fixed a <bug>, and <added> file1&&file2.</msg>" +
"</logentry>";
System.out.println("original string: "+str2);
//替换“&”:$1表示与(<msg>.*)的匹配子序列;$4表示与(.*</msg>)匹配的。
//&(?!amp;)表示匹配&而且后面不是amp;的字符串
//"$1&$3$4"得到的结果就是替换了<msg></msg>中的“&”为“&”
//由于每次只能替换掉一个“&”,所以循环执行替换,直到替换后与替换前的字符串相等。
String str1 = "";
while(!str2.equals(str1)){
str1 = str2;
str2 = str1.replaceAll("(<msg>.*)(&(?!amp;))(.*</msg>)", "$1&$3");
}
System.out.println("firstly replace \"&\": "+str2);
//替换“<”
str1 = "";
while(!str2.equals(str1)){
str1 = str2;
str2 = str1.replaceAll("(<msg>.*)(<)(.*</msg>)", "$1<$3");
}
System.out.println("then replace \"<\": "+str2);
//替换“<”
str1 = "";
while(!str2.equals(str1)){
str1 = str2;
str2 = str1.replaceAll("(<msg>.*)(>)(.*</msg>)", "$1>$3");
}
System.out.println("finally replace \">\": "+str2);
}
输出结果:
original string: <logentry revision='1'><msg>In this comment, I fixed a <bug>, and <added> file1&&file2.</msg></logentry>
firstly replace "&": <logentry revision='1'><msg>In this comment, I fixed a <bug>, and <added> file1&&file2.</msg></logentry>
then replace "<": <logentry revision='1'><msg>In this comment, I fixed a <bug>, and <added> file1&&file2.</msg></logentry>
finally replace ">": <logentry revision='1'><msg>In this comment, I fixed a <bug>, and <added> file1&&file2.</msg></logentry>
从结果可以看出达到了我想要的效果。由于没有在网上搜到相关的解决方案,也不知道该方法是不是常用的方法,效率怎么样。如果找到更好的方法,再继续更新。