String类replaceAll方法正则替换深入分析
作者网址:
https://my.oschina.net/shipley/blog/98973
背景:
前几天有人发了一个关于下面问题的贴,对这个有点好奇,故花时间做了点研究。
对单个反斜杠字符串替换成双斜杠的Java实现如下:
String s = "\\";
方法一:String sr1 = s.replaceAll("\\\\", "\\\\\\\\");
方法二:String sr1 = s.replaceAll("\\\\", "$0$0");
我第一眼看到比较困惑,下面慢慢来分析。
分析:
对String类的replaceAll(String reg, String replacement)方法分析
一、两点疑惑
A. 为啥第一个参数reg必须是”\\\\”?
B. 为啥第二个参数replacement 必须是”\\\\\\\\”?
二、解答
A.因为reg这个参数表示一个正则表达式,首先字符串“\\\\”被转义后代表的实际是字符串\\,这就是正则表达式,那么在正则表达式里也有转义,那么这个正则匹配的就是\
B.首先字符串“\\\\\\\\”被转义后实际代表的其实是字符串\\\\;
接下来才是重点:
查看源码replaceAll方法的实现如下
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
其中Pattern.compile(regex).matcher(this), 返回的是一个Matcher对象。
先简单介绍java.util.regex.Matcher类,是通过解释 Pattern 对 字符序列执行匹配操作的引擎,其中持有对当前Pattern对象和当前String对象的引用。
执行一次调用其find方法,即对字符串执行一次从左向右的以Pattern为正则的匹配,并记录下匹配结果字符串的开始和结束位置索引,以及更新一个记录当前匹配结果的分组groups。
顺藤摸瓜,进入Matcher类的replaceAll方法,继续查看源码,
public String replaceAll(String replacement) {
// 对当前Matcher类进行重置,即对其中记录匹配结果的开始和结束位置索引,以及分组信息重置
reset();
// 执行第一次搜索
boolean result = find();
if (result) {
// 第一次搜索匹配成功
// 用于记录最终的替换结果字符串
StringBuffer sb = new StringBuffer();
// 循环搜索
do {
// *重点在此方法内:用于将从上一次匹配子字符串的下一个索引位置开始,到当前匹配的子字符串的结束索引位置的所有字符 append到字符串sb中
// 有点绕,可以暂时跳过,下面会对该方法进一步分析
appendReplacement(sb, replacement);
result = find();
} while (result);
// 将从最后一次匹配子字符串的下一个索引位置,到字符串的结尾的所有字符append到字符串sb中
appendTail(sb);
return sb.toString();
}
return text.toString();
}
继续南下,进入Matcher类的appendReplacement方法,
public Matcher appendReplacement(StringBuffer sb, String replacement) {
...省略部分代码
// 用于跟踪replacement字符串的索引
int cursor = 0;
String s = replacement;// Java api源码也有垃圾代码啊,呵呵 (s局部变量并未在后续代码中被使用)
// 对当前匹配到子字符串替换后的结果字符串
StringBuffer result = new StringBuffer();
// 遍历replacement字符串
while (cursor < replacement.length()) {
char nextChar = replacement.charAt(cursor);
if (nextChar == '\\') {
// 重点1:当字符为\时,跳过,并获取其后面的字符,追加到result
cursor++;
nextChar = replacement.charAt(cursor);
result.append(nextChar);
cursor++;
} else if (nextChar == '$') {
// 重点2:当字符为$时,跳过,并获取其后面的数值,并以此如果$后面第一个不为数字则抛异常,
// Skip past $
cursor++;
// The first number is always a group
int refNum = (int)replacement.charAt(cursor) - '0';
// 此处代码用于计算$符号后的数值,数值结果赋予refNum
...省略部分代码
// group(refNum) 用于获取正则表达式第refNum个分组表示的字符串,不详说了
if (group(refNum) != null)
result.append(group(refNum)); // 追加到result
} else {
// 当前字符不为\ 或 $ 则直接追加到result
result.append(nextChar);
cursor++;
}
}
// 将从上一次匹配的子字符串的结尾索引,到当前匹配的第一个字符串索引的字符串追加到sb
// lastAppendPosition参数为上一次执行appendReplacement方法最后追加的字符在原始字符串中的索引位置。
// first 参数为当前待替换的子字符串的首个字符在原始字符串中的索引位置
sb.append(getSubSequence(lastAppendPosition, first));
// 将当前配置子字符串替换后的结果字符串追加到sb
sb.append(result.toString());
// 更新lastAppendPosition,供下一个匹配执行appendReplacement方法使用
lastAppendPosition = last;
/*
到此, sb中追加了当前匹配的子字符串与前一次匹配子字符串中间的字符,以及当前匹配子字符串被替换后的字符串
*/
return this;
}
分析结束。
总结
1、replaceAll中第二个参数replacement中,\有转义的作用,$用于获取分组匹配的当前子字符串
现在想想为什么要引入这个\转义的功能? 我的猜测是 ----- 因为引入了$符的分组功能,所以为了解决能输出$字符,故引入\转义功能
2、有助于理解Java的正则表达式;
3、世界上没有十全十美的代码,Java源码里也有垃圾代码,呵呵。
提供几个问题大家可以实践下:
1、对两个反斜杠字符串每个字符串都替换成双斜杠,如何实现?
即String s = "\\\\"; 替换成 String sr = "\\\\\\";
2、将单反斜杠替换成美元符,如何实现?
即String s = "\\"; 替换成 String sr = "$";
3、String s = "Jack is Rose's boyfriends."
使用$分组替换功能 替换成
String sr = "Rose is Jack's girlfriends."
String类replaceAll方法正则替换深入分析的更多相关文章
- 《java入门第一季》之类(String类常见方法小叙)
String类下面的构造方法和一些常见的方法: /* * 字符串:就是由多个字符组成的一串数据.也可以看成是一个字符数组. * 通过查看API,可以知道 * A:字符串字面值"abc&quo ...
- C++中string类的方法
C++ string类的方法 具体每个方法怎么使用,可以参考相应的链接. 总的链接为http://www.cplusplus.com/reference/string/string/(C++参考文档) ...
- string类find_first_not_of ()方法
string类find_first_not_of ()方法 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://xfqxj.blog. ...
- 深入分析Java的String类的方法与特点
字符串是任何编程语言都必须支持的变量类型,有些编程语言是直接提供了原生的变量类型,有些编程语言则使用语法特性以 SDK 的形式提供支持.在Java编程平台中,对字符串的支持使用了后者的形式,就是通过在 ...
- Java中String类的方法及说明
String : 字符串类型 一. String sc_sub = new String(c,3,2); // String sb_copy = new String(sb) ...
- String的replaceAll方法中的正则表达式用法
项目里面 需要对已手机号码进行 如下的显示 比如15088688388 要显示为150****8388的效果 实现这个简单的效果 方法有很多 我想试试用正则表达式去实现 查了点资料最终试出来以下方法可 ...
- 【转载】Java中String类的方法及说明
转载自:http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html String : 字符串类型 一. String sc_ ...
- 『Java』String类使用方法
Java中的字符串 java.lang.String类表示字符串类,Java程序中所有字符串文字都可以看作实现该类的实例. 特点: 字符串不可变:字符串的值在创建后不能在发生改变 public cla ...
- JDK6与JDK7中String类subString()方法的区别
1.subString()方法的作用 subString(int beginIndex, int endIndex)方法的返回的是以beginIndex开始到 endIndex-1结束的某个调用字符串 ...
随机推荐
- HDU1392Surround the Trees(凸包判断 + 求周长)
http://www.cnblogs.com/hmhard/archive/2013/02/05/2893035.html 这是判断三角区域那块写的不好. 判断凸包的方法: 1.将所有点按照y从小到大 ...
- 随便聊聊 SOA & SOAP & WebService 的一些东西,以及客户端开发的代码逻辑解析
http://blog.csdn.net/hikaliv/article/details/6459779 一天的时间调通了一个 WebService 的 Java 端的 C/S.一个 Android ...
- List<T> 转换 DataTable
public class List2DataTable { public static string GetClassName(Type type) { if (typ ...
- WinForm------GridControl中通过判断单元格文字显示不同字体颜色或背景色
- PHP内存溢出解决方案
一.内存溢出解决方案 在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案.还是用例子来说明这个问题,如下: 假定日志中存放的记录数为500000条,那么解决方案如下: ...
- Jquery实现textarea根据文本内容自适应高度
本文给大家分享的是Jquery实现textarea根据文本内容自适应高度,这些在平时的项目中挺实用的,所以抽空封装了一个文本框根据输入内容自适应高度的插件,这里推荐给小伙伴们. autoTextare ...
- securecrt中文乱码
1.直接打开Linux的terminal中文字符显示正常,但是用securecrt登陆后中文显示不正常 解决方法:securecrt字符集设置不对 路径:Options -> Session O ...
- MySQL取每组的前N条记录
一.对分组的记录取前N条记录:例子:取前 2条最大(小)的记录 .用子查询: SELECT * FROM right2 a WHERE > (SELECT COUNT(*) FROM right ...
- AspNet Identity and IoC Container Registration
https://github.com/trailmax/IoCIdentitySample TL;DR: Registration code for Autofac, for SimpleInject ...
- MyEclipse项目中的java文件的图标变成空心的问题
今天从SVN更新了一下整个工程,更新完成后发现工程的目录顺序变了,Java文件的图标也由原来实心"J"变成了空心的"J"了,网上查了一下,发现这样的问题不多,解 ...