java解析{{}}变量名以及文本内容替换操作
发短信、发邮件的时候经常会遇到模板内容需要替换成实际数据的问题,本文介绍从文本模板中解析出变量列表,以及参数填入后得到实际文本内容的办法:
/** * 根据正则表达式获取文本中的变量名列表 * @param pattern * @param content * @return */ public static List<String> getParams(String pattern, String content) { Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(content); List<String> result = new ArrayList<String>(); while (m.find()) { result.add(m.group(1)); } return result; } /** * 根据正则表达式将文本中的变量使用实际的数据替换成无变量的文本 * @param pattern * @param content * @param data * @return */ public static String parse(String pattern, String content, Map<String, String> data) { Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(content); StringBuffer sb = new StringBuffer(); while (m.find()) { String key = m.group(1); String value = data.get(key); m.appendReplacement(sb, value == null ? "" : value); } m.appendTail(sb); return sb.toString(); } public static void main(String[] args) { String content = "恭喜{{姓名}}报名成功,请凭报名编号{[code]}到现场参加活动"; String reg = "\\{\\{(.+?)\\}\\}"; List<String> params = getParams(reg, content); System.out.println(params); Map<String, String> data = new HashMap<String, String>(); data.put("姓名", "张三丰"); data.put("code", "930118"); String text = parse(reg, content, data); System.out.println(text); }
上面的代码介绍的是针对{{}}形式的变量值的解析办法,大家可以修改一下正则表达式,改成可以解析${}变量的办法
补充知识:java模板字符串优雅解析(占位符解析)
项目中常常需要解析字符串模板,比如user:{userId}:{userType}用于redis的key等,比较常见的做法就是使用String.format(“user:%s:%s”, 1, 1)方法,但个人感觉那样的模板不够明了,而使用模板解析器可更好地有助于解析此类字符串。
可使用map用于解析,也可使用对象进行解析,也可使用类似String.format可变参数进行解析,多样化解析对象值。有点类似于js的模板字符串${}。
也可自定义前缀后缀进行解析。如PlaceholderResolver.getResolver("{", “}”)该对象可解析{}该类型的占位符.
性能方面:
PlaceholderResolve解析结果
String.format解析结果
解析100w次,占位符解析比String.format平均都会快个0.4~0.5s,so 性能应该问题不大。最主要的是不需要调用太多的对象方法,自动解析,方便快捷。
源代码如下:
/** * 占位符解析器 * * @author meilin.huang * @version 1.0 * @date 2018-11-13 1:42 PM */ public class PlaceholderResolver { /** * 默认前缀占位符 */ public static final String DEFAULT_PLACEHOLDER_PREFIX = "${"; /** * 默认后缀占位符 */ public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}"; /** * 默认单例解析器 */ private static PlaceholderResolver defaultResolver = new PlaceholderResolver(); /** * 占位符前缀 */ private String placeholderPrefix = DEFAULT_PLACEHOLDER_PREFIX; /** * 占位符后缀 */ private String placeholderSuffix = DEFAULT_PLACEHOLDER_SUFFIX; private PlaceholderResolver(){} private PlaceholderResolver(String placeholderPrefix, String placeholderSuffix) { this.placeholderPrefix = placeholderPrefix; this.placeholderSuffix = placeholderSuffix; } /** * 获取默认的占位符解析器,即占位符前缀为"${", 后缀为"}" * @return */ public static PlaceholderResolver getDefaultResolver() { return defaultResolver; } public static PlaceholderResolver getResolver(String placeholderPrefix, String placeholderSuffix) { return new PlaceholderResolver(placeholderPrefix, placeholderSuffix); } /** * 解析带有指定占位符的模板字符串,默认占位符为前缀:${ 后缀:}<br/><br/> * 如:template = category:${}:product:${}<br/> * values = {"1", "2"}<br/> * 返回 category:1:product:2<br/> * * @param content 要解析的带有占位符的模板字符串 * @param values 按照模板占位符索引位置设置对应的值 * @return */ public String resolve(String content, String... values) { int start = content.indexOf(this.placeholderPrefix); if (start == -1) { return content; } //值索引 int valueIndex = 0; StringBuilder result = new StringBuilder(content); while (start != -1) { int end = result.indexOf(this.placeholderSuffix); String replaceContent = values[valueIndex++]; result.replace(start, end + this.placeholderSuffix.length(), replaceContent); start = result.indexOf(this.placeholderPrefix, start + replaceContent.length()); } return result.toString(); } /** * 解析带有指定占位符的模板字符串,默认占位符为前缀:${ 后缀:}<br/><br/> * 如:template = category:${}:product:${}<br/> * values = {"1", "2"}<br/> * 返回 category:1:product:2<br/> * * @param content 要解析的带有占位符的模板字符串 * @param values 按照模板占位符索引位置设置对应的值 * @return */ public String resolve(String content, Object[] values) { return resolve(content, Stream.of(values).map(String::valueOf).toArray(String[]::new)); } /** * 根据替换规则来替换指定模板中的占位符值 * @param content 要解析的字符串 * @param rule 解析规则回调 * @return */ public String resolveByRule(String content, Function<String, String> rule) { int start = content.indexOf(this.placeholderPrefix); if (start == -1) { return content; } StringBuilder result = new StringBuilder(content); while (start != -1) { int end = result.indexOf(this.placeholderSuffix, start); //获取占位符属性值,如${id}, 即获取id String placeholder = result.substring(start + this.placeholderPrefix.length(), end); //替换整个占位符内容,即将${id}值替换为替换规则回调中的内容 String replaceContent = placeholder.trim().isEmpty() ? "" : rule.apply(placeholder); result.replace(start, end + this.placeholderSuffix.length(), replaceContent); start = result.indexOf(this.placeholderPrefix, start + replaceContent.length()); } return result.toString(); } /** * 替换模板中占位符内容,占位符的内容即为map key对应的值,key为占位符中的内容。<br/><br/> * 如:content = product:${id}:detail:${did}<br/> * valueMap = id -> 1; pid -> 2<br/> * 经过解析返回 product:1:detail:2<br/> * * @param content 模板内容。 * @param valueMap 值映射 * @return 替换完成后的字符串。 */ public String resolveByMap(String content, final Map<String, Object> valueMap) { return resolveByRule(content, placeholderValue -> String.valueOf(valueMap.get(placeholderValue))); } /** * 根据properties文件替换占位符内容 * @param content * @param properties * @return */ public String resolveByProperties(String content, final Properties properties) { return resolveByRule(content, placeholderValue -> properties.getProperty(placeholderValue)); } /** * 根据对象中字段路径(即类似js访问对象属性值)替换模板中的占位符 <br/><br/> * 如 content = product:${id}:detail:${detail.id} <br/> * obj = Product.builder().id(1).detail(Detail.builder().id(2).build()).build(); <br/> * 经过解析返回 product:1:detail:2 <br/> * * @param content 要解析的内容 * @param obj 填充解析内容的对象(如果是基本类型,则所有占位符替换为相同的值) * @return */ public String resolveByObject(String content, final Object obj) { if (obj instanceof Map) { return resolveByMap(content, (Map)obj); } return resolveByRule(content, placeholderValue -> String.valueOf(ReflectionUtils.getValueByFieldPath(obj, placeholderValue))); } }
由于代码还有一些工具类的调用因为篇幅问题没有贴,如有需要可以去 https://gitee.com/objs/mayfly该项目中获取
以上这篇java解析{{}}变量名以及文本内容替换操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。
赞 (0)