首页 > 经验记录 > 利用 Java 的 Matcher#appendReplacement 方法配合正则实现模板语法、token填充功能

利用 Java 的 Matcher#appendReplacement 方法配合正则实现模板语法、token填充功能

应用开发时, 有人可能会有机会遇到需要自己制定模板语法的时候。 比如这几个场景:
1、 回复/评论/私聊 系统 的表情、链接 。 这种模块一般都不会采取富文本的形式来保存,  而是自己制定一个模板语法如 [默认表情: 滑稽]  然后在渲染时再渲染成HTML
2、系统消息推送时携带链接,   并不是每个运营人员都会学习HTML
3、自定义类似于 Markdown 的语法
 

此场景下的需求

输入参数:

这是一个模板字符串: #[百度|https://www.baidu.com] — #[谷歌|https://www.google.com]

输出参数:

这是一个模板字符串: <a href=’https://www.baidu.com’>百度</a> — <a href=’https://www.google.com’>谷歌</a>

 
 
 
如果说模板语法不一定能用到,  那么我想 token填充 应该是不少场景都会用到的, 很简单就能数出几个类似场景:
1、 短信发送,  短信模板内肯定会有几个 token 槽位。 如:    手机尾号为{{phone}} 的 {{user}} 你好, 你的验证码为:{{verifyCode}}
2、前端控件渲染,  vue就不用说了吧
3、站内信\站内消息等推送,  和短信一样,  都是会有模板存在的
 

此场景下的需求

输入模板:

这是一个模板字符串: <a href='{{link}}’>{{text}}</a>

定义 Tokens:

link=’https://www.baidu.com’        text=’链接’

渲染结果:

这是一个模板字符串: <a href=’https://www.baidu.com’>百度</a> — <a href=’https://www.google.com’>谷歌</a>

 
 

实现方式:

像这种场景,  那当然就是正则的出场时机了
有的小机灵鬼可能就知道, 可以用  replaceAll()  方法去替换呀! 这点确实是可以的。 但仅限于 token填充 这一个场景,对模板语法无能为力。
并且也会有性能上的问题,  因为你有多少个token, 就会有多少次替换操作。
 
这时候就可以轮到 Matcher#appendReplacement 方法上场了: 
使用 appendReplacement(StringBuffer sb, String replacement) 方法来可以实现渐进式的替换,就是根据正则进行匹配来一个个的替换, 然后截取替换完毕的内容追加到一个字符串里。
当执行所有的替换操作完成后,最后调用 public StringBuffer appendTail(StringBuffer sb) 方法,补充添加最后剩余的部分。
这样即可将一个模板字符串内所有的待替换项全部按需替换完毕。
 
 

下面是示例:

 
模板语法:

private static void template() {
        String template = "这是一个模板字符串: #[百度|https://www.baidu.com] -- #[谷歌|https://www.google.com]";
        //中间加了 ?  目的是非贪婪匹配
        String patternString = "#\\[(.+?\\|.+?)]";
        Matcher matcher = Pattern.compile(patternString).matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String[] split = matcher.group(1).split("\\|");
            String result = String.format("<a href='%s'>%s</a>", split[1], split[0]);
            matcher.appendReplacement(sb, result);
        }
        matcher.appendTail(sb);
        System.out.println(sb);
        //这是一个模板字符串: <a href='https://www.baidu.com'>百度</a> -- <a href='https://www.google.com'>谷歌</a>
    }

 
tokens 填充:

    private static void tokens() {
        //带token位置的字符串
        String template = "这是一个模板字符串: <a href='{{link}}'>{{text}}</a>";
        //定义token
        Map<String, String> tokens = new HashMap();
        tokens.put("link", "https://www.baidu.com");
        tokens.put("text", "链接");
        //生成匹配模式的正则表达式
        String patternString = "\\{\\{(" + tokens.keySet().stream().collect(joining("|")) + ")\\}\\}";
        Matcher matcher = Pattern.compile(patternString).matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, tokens.get(matcher.group(1)));
        }
        matcher.appendTail(sb);
        System.out.println(sb);
        //这是一个模板字符串: <a href='https://www.baidu.com'>链接</a>
    }

 
 

           


CAPTCHAis initialing...
EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00