【问题标题】:Template and Place holders algorithm模板和占位符算法
【发布时间】:2012-02-17 06:08:19
【问题描述】:

首先快速定义:)

  • 模板 - 可能包含占位符的字符串(例如:“hello [name]”)
  • Placeholder - 一个带有方括号的子字符串(例如:“hello [name]: 中的“name”)。
  • 属性映射 - 以字符串为值的有效对象

我需要编写一个代码,用属性映射中的匹配值替换占位符(连同括号)。

示例: 对于以下属性映射:

{
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
}

预期结果:

  • “你好名字”->“你好名字”

  • “你好[名字]”->“你好世界”

  • “[b]”->“c”

  • “[a]”->“c”(因为[a]->[b]->[c])

  • “[[b]]”->“我的”(因为[[b]]->[c]->我的)

  • “你好[我的][名字]”->“你好美丽的世界”

【问题讨论】:

  • 如果有一个循环会发生什么,比如 a -> [b] 和 b -> [a]?此外,是否所有决策都是强制的(也就是说,没有键映射到多个值?)
  • 当然,忽略循环。认为地图对象有效

标签: javascript algorithm templates placeholder


【解决方案1】:
var map = {
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
};

var str = "hello [my] [name] [[b]]";

do {
    var strBeforeReplace = str;
    for (var k in map) {
        if (!map.hasOwnProperty(k)) continue;
        var needle = "[" + k + "]";
        str = str.replace(needle, map[k]);
    }
    var strChanged = str !== strBeforeReplace;
} while (strChanged);

document.write(str); //hello beautiful world my

【讨论】:

  • 太棒了!这正是我所需要的!非常感谢
【解决方案2】:

@chris 的回答非常好,我只想提供一个使用正则表达式的替代解决方案,它可以“反过来”工作,即,不是通过查找属性中所有项目的“占位符版本”的出现map,但通过重复查找占位符本身的出现,并用属性映射中的相应值替换它。这有两个好处:

  1. 如果属性图变得非常大,这个解决方案应该有 更好的性能(但仍有待基准测试)。
  2. 可以通过调整正则表达式和替换函数轻松修改占位符和替换的工作方式(这里可能不是问题)。

当然,缺点是代码稍微复杂一些(部分原因是 JavaScript 缺乏使用自定义函数替换正则表达式匹配的好方法,所以这就是 substituteRegExp 的用途):

function substituteRegExp(string, regexp, f) {
    // substitute all matches of regexp in string with the value
    // returned by f given a match and the corresponding group values
    var found;
    var lastIndex = 0;
    var result = "";
    while (found = regexp.exec(string)) {
        var subst = f.apply(this, found);
        result += string.slice(lastIndex, found.index) + subst;
        lastIndex = found.index + found[0].length;
    }
    result += string.slice(lastIndex);
    return result;
}

function templateReplace(string, values) {
    // repeatedly substitute [key] placeholders in string by values[key]
    var placeholder = /\[([a-zA-Z0-9]+)\]/g;
    while (true) {
        var newString = substituteRegExp(string, placeholder, function(match, key) {
            return values[key];
        });
        if (newString == string)
            break;
        string = newString;
    }
    return string;
}

alert(templateReplace("hello [[b]] [my] [name]", {
    "name":"world",
    "my":"beautiful",
    "a":"[b]",
    "b":"c",
    "c":"my"
})); // -> "hello my beautiful world"

更新:我做了一些小分析来比较这两种解决方案(http://jsfiddle.net/n8Fyv/1/ 的 jsFiddle,我也使用了 Firebug)。虽然@chris 的解决方案对于小字符串更快(无需解析正则表达式等),但该解决方案对于大字符串(大约数千个字符)执行得更好。我没有比较不同大小的属性图,但预计会有更大的差异。

理论上,该解决方案的运行时间为 O(k n),其中 k 是占位符的嵌套深度,n 是字符串的长度(假设字典/哈希查找需要恒定时间),而@chris 的解决方案是 O(k n m) 其中 m 是属性映射中的项目数。当然,所有这些都只与大输入相关。

【讨论】:

  • 谢谢,写的真详细!
【解决方案3】:

如果您熟悉 .NET 的 String.Format,那么您应该看看 this JavaScript implementation。它也支持数字格式,就像String.Format

这是一个如何使用它的示例:

var result = String.Format("Hello {my} {name}", map);

但是,它需要进行一些修改才能执行递归模板。

【讨论】:

    猜你喜欢
    • 2015-05-10
    • 1970-01-01
    • 2015-05-20
    • 2017-05-20
    • 2020-09-18
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 2020-09-20
    相关资源
    最近更新 更多