首页 > 程序开发 > 软件开发 > Java >

java正则表达式

2011-08-09

在学习java正则表达式时,遇到三个问题。1、java字符串和正则模式的字符串很不清楚2、正则中有捕获组的概念,并且还能对捕获后的组进行字符串替换,即appendreplacement(stringbuffer sb, string replacement...

在学习java正则表达式时,遇到三个问题。

1、java字符串和正则模式的字符串很不清楚

2、正则中有捕获组的概念,并且还能对捕获后的组进行字符串替换,即appendreplacement(stringbuffer sb, string replacement)方法的原理不清楚

3、为什么在调用appendreplacement(stringbuffer sb, string replacement)方法之前需要对replacement中的"\"和"$"字符进行转义。

java正则表达式一般是对于字符串的操作,个人理解在正则表达式中,字符串有三个基本的概念:

第一,代码字符串:写在java文件中的字符串。

第二,内存字符串:代码字符串在内存中的形式。

第三,正则模式字符串:由pattern编译内存字符串形成的正则模式字符串。

比如在java代码中表示一个"\$"字符串,应该这样写

Java代码

string code = "\\$"; system.out.println("code: " + code);

输出结果 code: \$

因为在java代码中"\"表示转义字符,所以第一个"\"表示要转义后面的内容。在内存中,code内存字符串形式就是"\$"。

现在想写一个正则表达式匹配字符串"\$",代码如下:

Java代码

string code="\\$"; system.out.println("code: " + code); string patternstring ="\\\\\\$"; pattern pattern = pattern.compile(patternstring); matcher matcher = pattern.matcher(code); while(matcher.find()) { system.out.println("matcher:" + matcher.group()); }

输出结果 code:\$

matcher:\$

为什么匹配模式的java代码字符串是"\\\\\\$"。code在内存中形式是:\$,那正则模式字符串也应该是\$,在编译为模式字符串前的内存字符串应该是\\\$。正则模式字符串的第一个"\",在内存中应该是"\\"(正则模式中的\表示转义),而$在内存中应该是\$(正则模式串中$表示空白字符,所以需要转义),所以模式字符串在编译前在内存中的形式应该\\\$。内存的\\\$,再转换为java代码,应该是[color=red]"\\\\\\$"

在使用正则时经常用到捕获组,对于捕获到的组进行字符串替换,需要用到appendreplacement(stringbuffer sb, string replacement)方法。该方法对于第二个参数替换的字符串有特殊要求,如果replacement里有"\"字符串和"$"字符串则必须要进行转义。为什么了?可以看看源代码replacement的源码

[/color]

Java代码

public matcher appendreplacement(stringbuffer sb, string replacement) { // if no match, return error if (first < 0) throw new illegalstateexception("no match available"); // process substitution string to replace group references with groups int cursor = 0; string s = replacement; stringbuffer result = new stringbuffer(); while (cursor < replacement.length()) { char nextchar = replacement.charat(cursor); if (nextchar == &#39;\\&#39;) { cursor++; nextchar = replacement.charat(cursor); result.append(nextchar); cursor++; } else if (nextchar == &#39;$&#39;) { // skip past $ cursor++; // the first number is always a group int refnum = (int)replacement.charat(cursor) - &#39;0&#39;; if ((refnum < 0)||(refnum > 9)) throw new illegalargumentexception( "illegal group reference"); cursor++; // capture the largest legal group string boolean done = false; while (!done) { if (cursor >= replacement.length()) { break; } int nextdigit = replacement.charat(cursor) - &#39;0&#39;; if ((nextdigit < 0)||(nextdigit > 9)) { // not a number break; } int newrefnum = (refnum * 10) + nextdigit; if (groupcount() < newrefnum) { done = true; } else { refnum = newrefnum; cursor++; } } // append group if (group(refnum) != null) result.append(group(refnum)); } else { result.append(nextchar); cursor++; } } // append the intervening text sb.append(getsubsequence(lastappendposition, first)); // append the match substitution sb.append(result.tostring()); lastappendposition = last; return this; }

原来在替换的时候,程序会遍历replacement的每个字符,如果内存字符为&#39;\&#39;则不会把该字符放入到缓存result中而是把后面一个字符直接放入到缓存result中;如果字符为$符号,则会判断$字符后面的是不是数字,如果是数字则会认为是组引用,及把匹配组的字符串加到字符缓存result中。原来字符&#39;\&#39;和字符&#39;$&#39;在replacement中可以认为是关键字有特殊的作用。所以我们在调用此方法之前最好把replacement中"\"转换为"\\","$"转换为"\$"。

现在实验一下,把字符串中"y123y324"字符"y"替换成"$"。

Java代码

string patternstring = "(y)"; string code = "y123y432"; //system.out.println("code:" + code); string replacement = "$"; replacement = replacement.replaceall("\\$", "\\\\\\$"); pattern pattern = pattern.compile(patternstring); matcher matcher = pattern.matcher(code); stringbuffer sb = new stringbuffer(); while(matcher.find()) { matcher.appendreplacement(sb, replacement); } matcher.appendtail(sb); system.out.println(sb.tostring());

输出结果:$123$432

至于为什么replaceall里的第二个参数是这样的"\\\\\\$",其实看源码,replaceall也是调用了matcher类里的appendreplacement。分析方法可以参照前面的方法。

相关文章
最新文章
热点推荐