String.replaceAll与java.lang.IllegalArgumentException

                String.replaceAll与java.lang.IllegalArgumentException
0.应用场景(非真实应用,笔者设计)
在进行货币的转换时,需要将货币的单位根据不同国家的货币符号进行替换,例如:
中国:¥
美国:$
英国:£
此时表示货币单位的字段使用一个变量来表示,例如{curr}。
根据不同的区域设置,将变量替换为对应的货币符号。
1.CODE
笔者写了一个很简单的类,来实现这个功能,最初的代码如下:

2.问题一
执行上面的类,执行结果如下:

当出现异常或者错误时,解决方案有两种:
a.外事问Google,内事问Baidu
Google搜索了一下,原来{和}是正则表达式中的关键字,所以需要转义。
b.自己动手,Debug一下
在java.util.regex.Pattern.closure方法的2558行(笔者使用的JDK为1.4.2_15),有如下的代码:

即,如果出现{符号,并且后面的字符不是数字,那么就会抛出异常。
在JDK的文档中,对于正则表达式的关键字也有如下的说明:
Greedy quantifiers
X? - X, once or not at all
X* - X, zero or more times
X+ - X, one or more times
X{n} - X, exactly n times
X{n,} - X, at least n times
X{n,m} - X, at least n but not more than m times
 
Reluctant quantifiers
X?? - X, once or not at all
X*? - X, zero or more times
X+? - X, one or more times
X{n}? - X, exactly n times
X{n,}? - X, at least n times
X{n,m}? - X, at least n but not more than m times
 
Possessive quantifiers
X?+ - X, once or not at all
X*+ - X, zero or more times
X++ - X, one or more times
X{n}+ - X, exactly n times
X{n,}+ - X, at least n times
X{n,m}+ - X, at least n but not more than m times

解决方案:将{和}进行转义,将上面的类中的replaceAll的代码进行如下的修改:

此时运行的结果如下:
The price is ¥1000.00

3.问题二
上面的修改可以使程序正常运行,但是要使程序能够完全正常的运行,应该通过所有的测试用例。
下面将Locale设置为美国。此时我们想要输出的结果应该为:
The price is $1000.00
修改类的代码:
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.CHINA);
==>
DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.US);
运行程序,得到如下的输出:

这次通过使用Debug的方式(笔者偏向于这种方式,很多时候发现问题,自己找出并解决可以避免下次发生类似的错误,并且印象比较深刻,当然是在不花费太多时间为前提),可以发现问题出在:

这里字符/和$都是作为一种特殊情况来处理的,例子程序中替换的字符串为$,此时会使游标自增,而替换的字符串的长度为1,导致了ArrayIndexOutOfBoundsException。
而如果我们将替换字符修改为"$a",那么出现的异常变成了另外一种:
java.lang.IllegalArgumentException: Illegal group reference
问题发生的地方同样,当字符为$符号时,游标自增1,然后如果$的下一个字符的ASCII不是0~9之间,就会抛出上述异常。

究其原因,仍然是因为$也是正则表达式中的特殊符号,在JDK文档中的说明如下:
Boundary matchers
^ The beginning of a line
$ The end of a line

解决方案:对$字符进行转义。转义后即可正确的输出。

3.Better解决方案
众所周知,在属性文件中经常会使用{0},{1}这样的参数来进行运行时的消息替换。例如:
errorCode = The input age value {0} is invalid. Age value must be a integer.
这也是一种典型的Struts消息方式。
Struts是如何进行的替换呢,原来Struts使用了JDK提供的基础类java.text.MessageFormat。
MessageFormat可以通过传入一个String参数(消息)进行构造,然后通过成员方法format(Object)来进行格式化,这里Object可以传入字符串,字符串数组等。

这样,上面的类可以修改为:
4.总结
本文主要介绍了在使用String.replaceAll时容易出现的两个问题,即String.replaceAll内部使用了正则表达式,对正则表达式的关键字需要进行格外小心的处理。
同时介绍了java.text.MessageFormat类如何进行消息中参数的替换。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值