20

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

 3 years ago
source link: https://www.skypyb.com/2020/11/jishu/1660/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

应用开发时, 有人可能会有机会遇到需要自己制定 模板语法 的时候。 比如这几个场景:

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>
    }

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK