首先快速定义:)
我需要编写一个代码,用属性映射中的匹配值替换占位符(以及括号)。
例如: 对于以下属性映射:
{
"name":"world",
"my":"beautiful",
"a":"[b]",
"b":"c",
"c":"my"
}
预期结果:
“你好名字” - > “你好名字”
“你好[姓名]” - > “你好世界”
“[b]” - > “C”
“[a]” - > “c”(因为[a] - > [b] - > [c])
“[[b]]” - > “我的”(因为[[b]] - > [c] - > my)
“你好[我的] [姓名]” - > “你好美丽的世界”
答案 0 :(得分:2)
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
答案 1 :(得分:2)
@chris的答案非常好,我只是想提供一种替代解决方案,使用正则表达式“反过来”,即不是通过查找属性中所有项目的“占位符版本”的出现map,但通过反复查找占位符本身的出现次数,并用属性映射中的相应值替换它。这有两个好处:
当然,缺点是代码有点复杂(部分原因是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"
更新:我做了一些小的分析来比较两个解决方案(jsFiddle在http://jsfiddle.net/n8Fyv/1/,我也使用了Firebug)。虽然@chris的解决方案对于小字符串来说更快(不需要解析正则表达式等),但是对于大字符串(大约数千个字符),此解决方案执行得更好。我没有比较不同尺寸的属性地图,但期望更大的差异。
理论上,此解决方案具有运行时O( k n ),其中 k 是占位符和 n的嵌套深度是字符串的长度(假设字典/散列查找需要恒定时间),而@chris'解决方案是O( k n m < / em>)其中 m 是属性映射中的项目数。当然,所有这些只与大量投入有关。
答案 2 :(得分:0)
如果您熟悉.NET的String.Format
,那么您应该看一下this JavaScript implementation。它也支持数字格式,就像String.Format
一样。
以下是如何使用它的示例:
var result = String.Format("Hello {my} {name}", map);
但是,需要进行一些修改才能执行递归模板。