来自正则表达式的模板字符串

Template string from regex

假设我有以下 URL 路径:

/api/resource/:id

给定上下文对象 {id: 1} 路径将转换为 /api/resource/1

现在我想构建一个更复杂的路径模板:

/api/resource/:id(/relationships/:name)?

此处的 relationships 成员是可选的,因此两个上下文都可以匹配:

我希望能够使用一组有限的正则表达式魔术来构建这样的字符串。

如何实现这样的模板引擎?

在 node.js 中,您只需定义两个不同的模板:

routes.route('/api/resource/:id')
  .get....

routes.route('/api/resource/:id/relationships/:name')
  .get...

但是,正如 trincot 提到的,如果您说明您使用什么框架来构建此功能,将会很有帮助。

您可以在 replace 中使用带有回调函数的正则表达式:

function applyTemplate(template, obj) {
    return template.replace(/\(([^()]*):(\w+)([^()]*)\)\?|:(\w+)/g, 
        function (match, before, name1, after, name2) {
            let name = name1 || name2;
            return name in obj ? (before||'') + obj[name] + (after||'') : '';
        });
}

var result,
    template = "/api/resource/:id(/relationships/:name)?";

result = applyTemplate(template, {id: 1, name: 'rel1'});
console.log(result);

result = applyTemplate(template, {id: 1});
console.log(result);

这不会处理 ( )? 形式的嵌套括号。如果你需要,那么我建议有一个循环,首先解析所有这些可选表达式,直到剩下 none:

function applyTemplate(template, obj) {
    var repeat = true;
    while (repeat) {
        repeat = false;
        template = template.replace(/\(([^()]*):(\w+)([^()]*)\)\?/g, function (match, before, name, after) {
            repeat = true;
            return name in obj ? before + obj[name] + after : '';
        });
    }
    // Now replace the non-optionals:
    return template.replace(/:(\w+)/g, function (match, name) {
        return obj[name] || '';
    });
}

var result,
    // Nested example
    template = "/api/resource/:id(/relationships(/option/:option)?/:name)?";

result = applyTemplate(template, {id: 1, option: 'special', name: 'rel1'});
console.log(result);
result = applyTemplate(template, {id: 1, name: 'rel1'});
console.log(result);
result = applyTemplate(template, {id: 1});
console.log(result);

实际上,我发现 path-to-regex 完全符合我的要求。