java正则表达式义

[size=medium]
在学习java正则表达式时,遇到三个问题。
1、java字符串和正则模式的字符串很不清楚
2、正则中有捕获组的概念,并且还能对捕获后的组进行字符串替换,即appendreplacement(stringbuffer sb, string replacement)方法的原理不清楚
3、为什么在调用appendreplacement(stringbuffer sb, string replacement)方法之前需要对replacement中的"\"和"$"字符进行转义。

java正则表达式一般是对于字符串的操作,个人理解在正则表达式中,字符串有三个基本的概念:
第一,代码字符串:写在java文件中的字符串。
第二,内存字符串:代码字符串在内存中的形式。
第三,正则模式字符串:由pattern编译内存字符串形成的正则模式字符串。
比如在java代码中表示一个"\$"字符串,应该这样写
[/size]
          string code = "\\$";          system.out.println("code: " + code);     

[size=medium]
输出结果 code: \$

因为在java代码中"\"表示转义字符,所以第一个"\"表示要转义后面的内容。在内存中,code内存字符串形式就是"\$"。
现在想写一个正则表达式匹配字符串"\$",代码如下:
[/size]
          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());           }     

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

在使用正则时经常用到捕获组,对于捕获到的组进行字符串替换,需要用到appendreplacement(stringbuffer sb, string replacement)方法。该方法对于第二个参数替换的字符串有特殊要求,如果replacement里有"\"字符串和"$"字符串则必须要进行转义。为什么了?可以看看源代码replacement的源码:
[/color]
      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 == '\\') {                cursor++;                nextchar = replacement.charat(cursor);                result.append(nextchar);                cursor++;            } else if (nextchar == '$') {                // skip past $                cursor++;                // the first number is always a group                int refnum = (int)replacement.charat(cursor) - '0';                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) - '0';                    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;    }


[size=medium]
原来在替换的时候,程序会遍历replacement的每个字符,如果内存字符为'\'则不会把该字符放入到缓存result中而是把后面一个字符直接放入到缓存result中;如果字符为$符号,则会判断$字符后面的是不是数字,如果是数字则会认为是组引用,及把匹配组的字符串加到字符缓存result中。原来字符'\'和字符'$'在replacement中可以认为是关键字有特殊的作用。所以我们在调用此方法之前最好把replacement中"\"转换为"\\","$"转换为"\$"。
现在实验一下,把字符串中"y123y324"字符"y"替换成"$"。
[/size]
   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()); 

[size=medium]
输出结果:$123$432
至于为什么replaceall里的第二个参数是这样的"\\\\\\$",其实看源码,replaceall也是调用了matcher类里的appendreplacement。分析方法可以参照前面的方法。
[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值