String⽅法中replace和replaceAll的区别详解(源码分析)
replace() 和 replaceAll() 都是常⽤的替换字符串的⽅法:
两者都是全部替换,即把源字符串中的某⼀字符或字符串全部换成指定的字符或字符串。
如果只想替换第⼀次出现的,可以使⽤ replaceFirst()。这个⽅法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第⼀次出现的字符串;
另外,如果 replaceAll() 和 replaceFirst() 所⽤的参数据不是基于规则表达式的,则与replace()替换字符串的效果是⼀样的,即这两者也⽀持字符串的操作;;
注意:执⾏了替换操作后,返回⼀个新的对象,源字符串的内容是没有发⽣改变的。
源码分析
可以来看看源码中关于两个⽅法的定义,我分别摘取了⼀段:
/* String.class */
...
/**
* Replaces each substring of this string that matches the literal target sequence
* with the specified literal replacement sequence ...
* 翻译:⽤指定的⽂字替换序列替换与⽂字⽬标序列匹配的字符串的每个⼦字符串。
*/
public String replace(CharSequence target, CharSequence replacement) {
return String(),Pattern.LITERAL).
matcher(this).replaceAll(Matcher.String()));
}
...
/**
* Replaces each substring of this string that matches the given regular expression
* with the
* 翻译:将与给定正则表达式匹配的字符串的每个⼦字符串替换为给定的替换。
*/
public String replaceAll(String regex, String replacement) {
return Patternpile(regex).
matcher(this).replaceAll(replacement);
}
...
通过⽅法的定义,可以直接了当的看到:
replaceAll() 在定义它的时候,就被赋予可以匹配正则表达式的功能。
通过源码,也可以看到两点:
replaceAll() ⽅法没有传⼊参数 “Pattern.LITERAL”;
这⼀点点的不同,就决定了 replaceAll() ⽅法需要优先判断被替换的参数 regex 是不是⼀个正则表达式。如果是正则,执⾏正则替换;如果是字符串,执⾏字符串替换,此时和 replace() 就是⼀样的了。
replaceAll() 源码分析
我知道学技术的⼩伙伴都属于“刨根问底”栏⽬组的,下⾯我带⼤家看⼀看,参数 "Pattern.LITERAL"是怎么影响业务逻辑的:
它共调⽤了三个函数,作⽤分别是:
Patternpile(String regex) – 编译(解析)正则表达式,获得Pattern对象;
Pattern.matcher(CharSequence input) – 获取匹配器;
正则匹配两个字符之间的字符串placeAll(String replacement) – 替换字符串;
顾名思义,我们需要解释的重点,就在 Patternpile(String regex) ⽅法中。
Patternpile(String regex) 函数如下:
它返回的是⼀个Pattern对象。
Pattern的构造函数如下:
这个构造函数是 private 级别的,不能被其他类直接调⽤,只能通过 Pattern 类的 compile(String regex) 和 compile(String regex, int flags) 调⽤。
该构造函数调⽤了 compile(),对 regex 参数的处理就发⽣在这个函数⾥⾯!!
Patternpile()函数如下:
其中,①中的参数"LITERAL"就是我们上⾯提到的那⼀点点不⽤(不清楚的可以再回看⼀下);
①处的 if – else 语句,决定②处是否执⾏;
②处的 matchRoot = expr(lastAccept);就是获得正则表达式匹配根结点的⽅法,若执⾏此⽅法,则开始进⾏正则表达式的匹配。
好了,再往下的代码我就不再演⽰了,有兴趣的⼩伙伴可以⾃⼰看⼀看。
代码论证
说了很多理论的东西,写⼏⾏代码验证下:
@Test
public void replaceTest() {
String str1 = "Aoc.Iop.Aoc.Iop.Aoc"; //定义三个⼀样的字符串
String str2 = "Aoc.Iop.Aoc.Iop.Aoc";
String str3 = "Aoc.Iop.Aoc.Iop.Aoc";
String str11 = place(".", "#"); // str11 = "Aoc#Iop#Aoc#Iop#Aoc"
String str22 = placeAll(".", "#"); // str22 = ">>>####"
String str33 = placeFirst(".", "#"); // str33 = "#oc.Iop.Aoc.Iop.Aoc"
}
由于“.”属于正则表达式的符号,所以 replaceAll() ⽅法执⾏的是正则替换。
转义符号 – “\”,需要格外注意下:
“\” 在 java 中是⼀个转义字符,所以需要⽤两个代表⼀个。
例如 System.out.println(“\\”);只打印出⼀个 “\”;
“\”也是正则表达式中的转义字符(replaceAll()的参数就是正则表达式),也需要⽤两个代表⼀个。
所以:“\\\\”会被j ava 转换成 “\\”,“\\” ⼜会被正则表达式转换成“\”。
看⼀个例⼦:
@Test
public void replaceTest() {
String str1 = "blog.csdn/weixin_44259720/";
String str2 = "blog.csdn/weixin_44259720/";
String str11 = place("/", "\\"); // 转义
String str22 = placeAll("/", "\\\\"); // 转义 + 正则匹配
}
输出结果相同:
str11 = "blog.csdn\weixin_44259720\"
str22 = "blog.csdn\weixin_44259720\"
⼩结
replace 的参数是 char 和 CharSequence,即可以⽀持字符的替换,也⽀持字符串的替换(CharSequence 即字符串序列的意思,说⽩了也就是字符串);
replaceAll 的参数是 regex,即基于正则表达式的替换。⽐如,可以通过 replaceAll ("\d", “*”) 把⼀个字符串所有的数字字符都换成星号;String 类执⾏了替换操作后,返回⼀个新的对象,源字符串的内容是没有发⽣改变的。
————————————————
版权声明:本⽂为CSDN博主「⽥潇⽂」的原创⽂章,遵循CC 4.0 BY-SA版权协议,转载请附上原⽂出处链接及本声明。
原⽂链接:blog.csdn/weixin_44259720/article/details/88070518
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
双字节符号正则
« 上一篇
SHELL查字符串中包含字符的命令
下一篇 »
发表评论