String字符串替换的一个诡异问题
程序员文章站
2022-04-15 20:26:01
...
将字符串中的数字替换成$D
希望将以下字符串中的数字替换为$D字符
ab1cd2
我们知道String有3个用于字符替换的方法,分别是:
由于我们希望所有替换,因此使用如下方法:
代码1:StringReplaceTest
小小代码现诡异异常
运行StringReplaceTest,控制台却没有返回正确的结果,而是抛出如下的异常:
java.lang.IllegalArgumentException: Illegal group reference
at java.util.regex.Matcher.appendReplacement(Matcher.java:713)
at java.util.regex.Matcher.replaceAll(Matcher.java:813)
at java.lang.String.replaceAll(String.java:2189)
at com.hsit.euler.qform.engine.jdbc.StringReplaceTest.testReplace(StringReplaceTest.java:17)
比较诡异吧,难道是JDK的BUG???
剥丝入茧,原来如此
其实String的replaceAll()及replaceFirst()方法内部都是调用java.util.regex.Matcher的String replaceAll(String replacement)方法的。让我们把刚才的诧异放在一边,好好看下这个方法的Javadoc,掐头去尾,主要是这段:
* <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
* the replacement string may cause the results to be different than if it
* were being treated as a literal replacement string. Dollar signs may be
* treated as references to captured subsequences as described above, and
* backslashes are used to escape literal characters in the replacement
* string.
原来是我们的替换目标串中包含了$这个特殊的字符,因为替换串使用这个引用正则表达式匹配的组,$0代表匹配项,$1代表第1个匹配分组,$1代表第2个匹配分组--终于真相大白了,是我们闯了雷区了
来看一个例子加深一个印象:
李鬼出来,李逹进去
李鬼现形,处理起来自然简单:
小评一下
如果JDK可以再分析一下$,将$N即N是数字时才对其进行特殊处理,否则就不当成特殊字符,是不是更好一些呢?
也许这样并不好,必须这样造成Matcher方法为了这个小概率事件做很多复杂的检查,结果是得不偿失的。还是遇到特殊字符报异常,让开发者去处理更好些,这是28原来取舍得当的一个API设计。既然$是特殊字符,开发者绕过即可。
希望将以下字符串中的数字替换为$D字符
引用
ab1cd2
我们知道String有3个用于字符替换的方法,分别是:
- String replace(CharSequence target, CharSequence replacement):将字符串中出现的target替换成replacement;
- String replaceAll(String regex, String replacement):regex是一个正则表达式,将字符串中匹配的子字符串替换为replacement;
- String replaceFirst(String regex, String replacement):和replaceAll(..)类似,只不过只替换第一个出现的地方。
由于我们希望所有替换,因此使用如下方法:
代码1:StringReplaceTest
public class StringReplaceTest { @Test public void testReplace(){ String str = "ab1cd2"; System.out.println(str.replaceAll(str, "$D")); } }
小小代码现诡异异常
运行StringReplaceTest,控制台却没有返回正确的结果,而是抛出如下的异常:
引用
java.lang.IllegalArgumentException: Illegal group reference
at java.util.regex.Matcher.appendReplacement(Matcher.java:713)
at java.util.regex.Matcher.replaceAll(Matcher.java:813)
at java.lang.String.replaceAll(String.java:2189)
at com.hsit.euler.qform.engine.jdbc.StringReplaceTest.testReplace(StringReplaceTest.java:17)
比较诡异吧,难道是JDK的BUG???
剥丝入茧,原来如此
其实String的replaceAll()及replaceFirst()方法内部都是调用java.util.regex.Matcher的String replaceAll(String replacement)方法的。让我们把刚才的诧异放在一边,好好看下这个方法的Javadoc,掐头去尾,主要是这段:
引用
* <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
* the replacement string may cause the results to be different than if it
* were being treated as a literal replacement string. Dollar signs may be
* treated as references to captured subsequences as described above, and
* backslashes are used to escape literal characters in the replacement
* string.
原来是我们的替换目标串中包含了$这个特殊的字符,因为替换串使用这个引用正则表达式匹配的组,$0代表匹配项,$1代表第1个匹配分组,$1代表第2个匹配分组--终于真相大白了,是我们闯了雷区了
来看一个例子加深一个印象:
@Test public void testReplace2(){ String str = "刘备是张飞的小弟"; System.out.println(str.replaceAll("(刘备)是(张飞)", "$2是$1")); //=>张飞是刘备的小弟 }
李鬼出来,李逹进去
李鬼现形,处理起来自然简单:
@Test public void testReplace(){ String str = "ab1cd2"; System.out.println(str.replaceAll(str, "\\$D")); //=>ab$Dcd$D }
小评一下
如果JDK可以再分析一下$,将$N即N是数字时才对其进行特殊处理,否则就不当成特殊字符,是不是更好一些呢?
也许这样并不好,必须这样造成Matcher方法为了这个小概率事件做很多复杂的检查,结果是得不偿失的。还是遇到特殊字符报异常,让开发者去处理更好些,这是28原来取舍得当的一个API设计。既然$是特殊字符,开发者绕过即可。
上一篇: 再次开刷IBM的垃圾 数据库
下一篇: UTF16和UTF8
推荐阅读
-
JavaScript实现替换字符串中最后一个字符的方法
-
C语言:字符串替换空格:请实现一个函数,把字符串中的每个空格替换成“%20”。
-
模板字符串替换教程,实现一个 render(template, context) 方法,将 template 中的占位符用 context 填充
-
通过V8源码看一个关于JS数组排序的诡异问题
-
9、试编写程序,输入一个字符串,再输入一个字符ch,将字符串中所有的ch字符替换为字符’*’。 要求定义和调用函数mChar(s, c ),该函数将字符串s中出现的所有c字符替换为’*’。
-
java的String字符串不相等判断问题
-
php多个字符串替换成同一个的解决方法
-
将指定字符串中的一个或多个格式项替换为指定对象的字符串表示形式。
-
分享一个诡异的可见性问题
-
java多线程定时器和java判断一个时间是否在时间区间内和用正则表达式获取String字符串之间的数据