String 方法 replaceFirst 、replaceAll 和 No group Exception

本文探讨了在使用Java的Matcher进行字符串替换时遇到的IndexOutOfBoundsException异常问题,并详细解释了该问题是由替换字符串中的特殊字符“$”引起的。通过了解这一特殊情况,作者找到了解决问题的方法。
今天被OA的一个问题搞得很无语,m.appendReplacement(sb, bodyArr[j]);报索引溢出的异常,找了半天的原因。后来几经周折才连接正式系统,跟踪里面的异常。
结果发现是String的使用过程中出现节点越界
java.lang.IndexOutOfBoundsException: No group 2
at java.util.regex.Matcher.group(Matcher.java:355)
at java.util.regex.Matcher.appendReplacement(Matcher.java:585)
at java.util.regex.Matcher.replaceFirst(Matcher.java:701)
at java.lang.String.replaceFirst(String.java:1630)
当时我就纳闷,contentStr.replaceFirst(fromStr, toStr) 这方法中处理的内容会越界?why?
contentStr,fromStr, toStr在项目中都是不可能为null,即便为null值那也应该是抛NullpointException异常才对;又或者压根没替换,那也不会有异常啊......
说实话,当时的我压根不会想到是JDK API本身的问题,那些代码逻辑都是几经磨练和测试okay后才成为了API的,肯定是我写代码的某些地方出了问题。可就是找不出破绽来。
只好到google谷歌了一下,结果发现有网友留言说此种情况算是Matcher的一个bug来的。
晕,之前居然老以为是自己代码出了漏洞。看来今后不能那么迷信权威了。
结果那网友说了是Matcher做替换时replaceAll 或者 replaceFirst 时,会对字符串中的“$”符号敏感,出现IndexOutOfBoundsException的问题,如上面的contentStr.replaceFirst(fromStr, "xx$xx")就会出错。摘录下网友的留言 in blue:
You have to track through the documentation quite carefully to discover that the characters \ and $ have a special 
meaning in the replacement string.  It could be helpful to copy this sentence from Matcher.replaceAll into all 
of String.replaceFirst, String.replaceAll, and Matcher.replaceFirst:

"Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than 
if it were being treated as a literal replacement string."
呵呵,这才想起似乎之前测试数据库中都没有含“$”符号的数据,偏巧正式数据库中有这些记录。 额的神!难怪之前测不出来。
不过总算知道问题根源了,呵呵,强行过滤Str中的“$”符号,替换后再还原它的“$”面目。
搞定!!!
endorTextModule = “#Compare#退还保费=#GuEndorMain.Currency##GuEndorRisk.ChangePremium#(不含税保费#GuEndorMain.Currency##GuEndorRisk.ChangeSumGrossPremiumNotTax#,增值税#GuEndorMain.Currency##GuEndorRisk.ChangeTaxAmount#)”; endorTextModule=endorTextModule.replaceFirst(“#Compare#”, “”); endorTextModule = parseEndorText(endorNo, policyNo,riskCode, endorTextModule, pattern); private String parseEndorText(String endorNo, String policyNo,String riskCode, String text, Pattern pattern) throws Exception { if (text == null || “”.equals(text.trim())) { return “”; } StringBuilder buffer = new StringBuilder(); Matcher matcher = pattern.matcher(text); while (matcher.find()) { buffer.setLength(0); List list = getExpressionValue(matcher.group().replaceAll(“#”, “”), endorNo, policyNo,riskCode); // buffer.append(leftInclude); if(list!=null && list.size()>0){ Object obj=list.get(0); if(obj!=null){ buffer.append(list.get(0).toString()); } } // buffer.append(rightInclude); text = text.replaceAll(matcher.group(), buffer.toString()); } return text; } public List getExpressionValue(String expression, String endorNo, String policyNo,String riskCode) { if(expression.indexOf(".")<0){ return null; } String[] strArr = expression.split("\\."); String tableName = strArr[0]; String fieldName = strArr[1]; String condition = null; StringBuilder buffer = new StringBuilder(); if (tableName != null && tableName.trim().toLowerCase().indexOf("policy") > 0) { buffer.append(" policyNo='"); buffer.append(policyNo); } else { buffer.append(" endorNo='"); buffer.append(endorNo); } buffer.append("'"); if(tableName.trim().toLowerCase().indexOf("risk") > 0){ buffer.append(" and riskCode='"); buffer.append(riskCode); buffer.append("'"); } condition = buffer.toString(); List list = guEndorEndorTextDao.findProperty(tableName, fieldName, condition); List returnList = new ArrayList(); //将日期格式转换为:YYYY年MM月DD日 if("ValidDate".equalsIgnoreCase(fieldName) || "EndDate".equalsIgnoreCase(fieldName)){ if(list != null ){ for(int i = 0; i < list.size(); i ++){ Object obj = list.get(i); SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); //Resources.getMessage("DefaultDateFormatStr") obj = sdf.format(obj); returnList.add(obj); } } }else if("guendorrisk".equals(tableName.toLowerCase()) && "changepremium".equals(fieldName.toLowerCase())){ if(list != null ){ DecimalFormat df = null;//批头退还、加收保费金额,小数点需保留2位小数.格式化 add by cong 2012/04/22. for(int i = 0; i < list.size(); i ++){ Object obj = (Object)list.get(i); df = new DecimalFormat("0.00"); obj = df.format(Math.abs((new Double(obj.toString())).doubleValue())); returnList.add(obj); } } }else{ returnList = list; } return returnList; } #GuEndorRisk.ChangePremium# = -500,输出值为500,是在哪一步做的转换,解析代码用中文表达
06-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值