java 批量替换字符串_# Java 一步一步实现高逼格的字符串替换工具(二)
Java 一步一步实现高逼格的字符串替换工具(二)
上一篇实现了一个用于字符串替换的方法,主要是利用 正则 + jdk的字符串替换,本篇则会再之前的基础上走一个扩展
1. 之前的方法存在的问题
先把上一篇的两个方法贴下,研究下有什么问题,然后再看下可以怎么去改进
// 获取patter的过程较为负责,这里初始化时,做一次即可
private static Pattern pattern;
static {
pattern = Pattern.compile("((?<=\\{)([a-zA-Z_]{1,})(?=\\}))");
}
/**
* 字符串替换, 将 {} 中的内容, 用给定的参数进行替换
*
* @param text
* @param params
* @return
*/
public static String format(String text, Map params) {
// 把文本中的所有需要替换的变量捞出来, 丢进keys
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
String key = matcher.group();
// text = StringUtils.replace(text, "{" + key + "}", params.get(key) + "");
text = text.replaceAll("\\{" + key + "\\}", params.get(key) + "");
}
return text;
}
public static List batchFormat(String text, List> params) {
List keys = new ArrayList<>();
// 把文本中的所有需要替换的变量捞出来, 丢进keys
Matcher matcher = pattern.matcher(text);
int tempIndex = 0;
while (matcher.find()) {
String key = matcher.group();
if (keys.contains(key)) {
continue;
}
text = StringUtils.replace(text, key, tempIndex + "");
tempIndex++;
keys.add(key);
}
List result = new ArrayList<>(params.size());
String[] tempParamAry = new String[keys.size()];
for (Map param : params) {
for (int i = 0; i < keys.size(); i++) {
tempParamAry[i] = param.get(keys.get(i)) + "";
}
result.add(MessageFormat.format(text, tempParamAry));
}
return result;
}
一个单个替换,一个批量替换,我们一个一个分析,首先看
1. public static String format(String text, Map params)
正则替换效率问题
String.replaceAll() 这个也是走的正则替换, 从我们的业务场景来看,有更好的替换
apache的 commons-lang 有个 StringUtils 工具类, 我们可以用里面的 replace 方法进行代替, 上面注释的就是我们推荐的使用方式
2. public static List batchFormat(String text, List> params)
这个的实现原理比较简单
先用正则把所有需要替换的捞出来, 放在列表中, 并将坑位用数字来替换
然后使用 MessageFormat.format 进行替换
这个流程比较清晰简单,对于 MessageFormat.format 却发现一个诡异的问题,当text中包含单引号时,后面的不会被替换, 测试case如下
public String replace(String text, Object... args) {
return MessageFormat.format(text, args);
}
@Test
public void testReplace2() {
String text = "hello {0}, welcome to {1}!";
String user = "Lucy";
String place = "China";
String ans = replace(text, user, place);
System.out.println(ans);
text = "hello {0}, welcome to {2} ! what's a good day! today is {1}!";
ans = replace(text, "Lucy", new Date(), "HangZhou");
System.out.println(ans);
}
输出如下:
debug到源码去看下,然后发现在生成 MessageFormat对象的实现中,单引号内部有特殊用途,认为两个单引号之间的为一个整体,不做替换
String text = "hello {0}, welcome to {2} ! what's {0}' a good day! today is {1}!";
String ans = MessageFormat.format(text, "Lucy", new Date(), "HangZhou");
System.out.println(ans); // 输出 hello Lucy, welcome to HangZhou ! whats {0} a good day! today is 17-3-28 下午5:54!
2. 改进++
对上面的正则获取key,然后再调用 MessageFormat.format()的方式不满意,特别是后者的潜规则还不少,我们要实现一个纯粹的,高效的,可扩展的替换工具,应该这么玩?
既然已经深入了MessageFormat的源码,那么就简单了,把他的实现逻辑抠出来,砍掉各种潜规则,我们自己来实现即可
新版的设计思路:
- 首先将文本进行拆分
- 以`{}`作为分割, 大括号前后的各自作为新的`Word`; 大括号内的也作为独立的`Word`
- 将拆分的`Word` 塞入一个数组中
- 遍历上面的数组,替换变量
- 返回想要的结果
实现如下:
public static String formatV2(String text, Map params) {
StringBuilder stringBuilder = new StringBuilder();
int startIndex = 0;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '{') {
if (startIndex > 0) {
stringBuilder.append(text.substring(startIndex, i));
}
startIndex = i + 1;
continue;
}
if (text.charAt(i) == '}') {
stringBuilder.append(params.get(text.substring(startIndex, i)));
startIndex = i + 1;
}
}
if (startIndex < text.length()) {
stringBuilder.append(text.substring(startIndex));
}
return stringBuilder.toString();
}
/**
* 规定大括号中不能再次出现大括号, 即不允许迭代替换
*
* @param text
* @param paramsList
* @return
*/
public static List batchFormatV2(String text, List> paramsList) {
List textList = splitText2words(text);
List result = new ArrayList<>();
StringBuilder stringBuilder;
for (Map params: paramsList) {
stringBuilder = new StringBuilder();
for (Word word: textList) {
stringBuilder.append(replaceWord(word, params));
}
result.add(stringBuilder.toString());
}
return result;
}
private static String replaceWord(Word word, Map params) {
if (word.getIsReplaceKey()) {
return params.get(word.getWord()) + "";
} else {
return word.getWord();
}
}
/**
* 将文本根据{}进行分割
*
* 如: {place} is a good place, what do you think {user}?
* 分割:
* - Word("place", true)
* - Word(" is a good place, what do you think ", false)
* - Word("user", true)
* - Word("?", false)
*
* @param text
* @return
*/
private static List splitText2words(String text) {
List textList = new ArrayList<>();
int startIndex = 0;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '{') {
if (startIndex > 0) {
textList.add(new Word(text.substring(startIndex, i), false));
}
startIndex = i + 1;
continue;
}
if (text.charAt(i) == '}') {
textList.add(new Word(text.substring(startIndex, i), true));
startIndex = i + 1;
}
}
if (startIndex < text.length()) {
textList.add(new Word(text.substring(startIndex), false));
}
return textList;
}
private static class Word {
private String word;
/**
* true 则表示保存的是需要被替换的值
*/
private Boolean isReplaceKey;
public Word(String word, Boolean replaceKey) {
this.word = word;
this.isReplaceKey = replaceKey;
}
public String getWord() {
return word;
}
public Boolean getIsReplaceKey() {
return isReplaceKey;
}
@Override
public String toString() {
return "Word{" +
"word='" + word + '\'' +
", isReplaceKey=" + isReplaceKey +
'}';
}
}
至此,一个算是不错的文本替换工具类出来了,想想还有什么可以改进的地方么?
简单的字符串进行替换有点low,如果我想在 {} 中执行一些表达式可以怎么玩 ?
下一篇则将精力主要集中在 {} 中value替换的玩法上
java 批量替换字符串_# Java 一步一步实现高逼格的字符串替换工具(二)相关推荐
- java privatekey输出字符串_[Java教程]根据字符串(String)生成公钥(PublicKey)和私钥(PrivateKey)对象_星空网...
根据字符串(String)生成公钥(PublicKey)和私钥(PrivateKey)对象 2012-05-29 0 1.字符串生成公钥对象 PublicKey /** * 实例化公钥 * * @re ...
- java 基础面试 英文_[Java面试] 面试java基础总结大全
原标题:[Java面试] 面试java基础总结大全 基础知识: 1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. ...
- java查看日志命令_[Java教程]【Linux】linux查看日志文件内容命令tail、cat、tac、head、echo...
[Java教程][Linux]linux查看日志文件内容命令tail.cat.tac.head.echo 0 2017-11-14 12:00:29 linux查看日志文件内容命令tail.cat.t ...
- java 内存泄露 书籍_[Java教程]一次艰难的内存泄露排查,BeanUtils 的锅
[Java教程]一次艰难的内存泄露排查,BeanUtils 的锅 0 2020-10-29 18:24:42 现象 通过jstat -gcutil pid 5000 ,发现fgc次数很多而且频繁,此时 ...
- java实现计算器框架_[Java小程序] 实现简单计算器
这学期没事学了一点点Java,想写个程序练手,因为只学了一点点,所以暂时只能先写个实现简单功能的计算器练练.感觉写完后不是很好,如果路过的哪位高手给点建议,小弟万分感激啊. 由于期末来了,没太多时间, ...
- java视、频_[java视频]感人故 事视 频网 站上那找~~~
感人故 事视 频网 站上那找~~~ 问题补充:感人故 事视 频网 站上那找~~~ ●呵呵,你问对人了,感人故事就去"新浪show",现在是新浪期下的网站,运行稳定,观看流畅,上传简 ...
- java 历遍 类_[Java] 遍历指定包名下所有的类(支持jar) | 学步园
项目需要,仅做记录. 支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度. 通过Thread.currentThread().getContextClas ...
- java语言金山打字_[Java教程]java实现 swing模仿金山打字 案例源码
[Java教程]java实现 swing模仿金山打字 案例源码 0 2014-11-17 12:00:21 java实现 swing模仿金山打字 案例源码,更多Java技术就去Java教程网.http ...
- java得到相对路径_[Java]JAVA获取相对路径问题的解决
1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如: C:xyz est.txt 代表了test.txt文件的绝对路径.http://www. ...
最新文章
- 乐山师范计算机科学与技术怎么样,乐山师范学院计算机科学与技术(本科)教育概况...
- 关于 Visual Studio 2010
- jquery问题,如何调用带this的函数?
- ipc620中文版最新版本_(一)Windows10 家庭中文版Docker安装 搭建docker开发环境
- Caffe自己修改训练方法
- Oracle数据库基本概念理解(3)
- jquery学习之-查找父元素方法parent() parents() closest()的区别
- 上手深度学习之前,我们先聊聊“数学”
- 华为NP课程笔记24-BFD
- 短时傅里叶变换原理解
- itunes不能读取iPhone的内容,请前往iPhone“偏好设置”的“摘要”选项卡,然后单击“恢复”
- 使用纯JavaScript实现全网页动态樱花飘落特效
- qq传输文件为什么服务器忙,qq传送离线 接收文件很慢怎么回事
- 网站如何做域名转移?闲置域名要及时处理
- <C++>初识多态,剖析virtual关键字
- 关于 intell IDEA 的代码自动提示功能没有,删了导包也不报红 (已解决)
- LINGO编程(基础)
- python中的下划线_讲解
- 【学习笔记】群论基础
- 对于电子签名、CA、证书的理解
热门文章
- 迁移python虚拟环境搭建_python虚拟环境virtualenv创建与迁移
- Paging Structures in the Different Paging Modes
- Linux之hugepage大页内存理论
- 我的世界服务器自定义怪物怎么用,我的世界怪物属性自定义教程 怪物属性代码一览...
- c查看变量类型_Python入门对象与变量
- javascript调用一个函数(对象),new和直接调用的区别
- Django如何使用多个数据库
- java垃圾回收GC(学习笔记)
- 30秒明白tcp的3次握手
- 次表面散射材质_游戏开发者怎么做出以假乱真的画面效果?大气散射渲染了解一下...