此函数循环遍历JavaScript嵌套数组(递归)并替换其中的字符串:
function replaceRecur(tree, str, newStr) {
for (var i = 1; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
replaceRecur(tree[i], str, newStr)
} else {
tree[i] = tree[i].replace(str, newStr)
}
}
}
用法示例:
function replaceQuotes(tree, callback) {
var str1 = /"(?=\b)/g
, str2 = /"(?!\b)/g
, newStr1 = '“'
, newStr2 = '”'
replaceRecur(tree, str1, newStr1)
replaceRecur(tree, str2, newStr2)
callback(null, tree)
}
我应该如何修改replaceRecur
,以便每个参数允许两个值?
示例:
function replaceQuotes(tree, callback) {
var str = ['/"(?=\b)/g/', '"(?!\b)/g']
, newStr = '“ ”' // not sure whether to use arrays or strings
// what's more common?
replaceRecur(tree, str, newStr)
callback(null, tree)
}
(原因是,我不想重复replaceRecur
,str
和newStr
两次。我想保留代码DRY。)
修改
示例输入(以防万一):
[ 'markdown',
[ 'para', '“a paragraph”' ],
[ 'hr' ],
[ 'para', '\'another paragraph\'' ],
[ 'para', 'test--test' ],
[ 'para', 'test---test' ],
[ 'bulletlist',
[ 'listitem', '“a list item”' ],
[ 'listitem', '“another list item”' ] ] ]
答案 0 :(得分:3)
创建一个函数,该函数执行结构的递归遍历并调用值的回调。然后,您可以将替换函数编写为传入的回调函数:
function traverse(tree, callback) {
for (var i = 0; i < tree.length; ++i) {
if (Array.isArray(tree[i]))
traverse(tree[i], callback);
else
tree[i] = callback(tree[i]);
}
}
function replaceTwo(tree, s1from, s1to, s2from, s2to) {
traverse(tree, function(element) {
return element.replace(s1from, s1to).replace(s2from, s2to);
});
}
您现在可以编写各种不同的函数来转换树内容,而无需重写递归部分。
答案 1 :(得分:1)
不幸的是,JavaScript中没有重载。
一个干净的解决方案是使用replaceRecur
,但在内部检查typeof
个参数,以确定您是否要使用_replaceRecur2
或_replaceRecur1
function replaceRecur(tree, arg1, arg2) {
if(typeof(arg1) === "function"){
_replaceRecur2(tree, arg1);
} else {
_replaceRecur1(tree, arg1, arg2);
}
}
function _replaceRecur1(tree, str, newStr) {
for (var i = 1; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
_replaceRecur1(tree[i], str, newStr)
} else {
tree[i] = tree[i].replace(str, newStr)
}
}
}
function _replaceQuotes2(tree, callback) {
var str1 = /"(?=\b)/g
, str2 = /"(?!\b)/g
, newStr1 = '“'
, newStr2 = '”'
_replaceRecur1(tree, str1, newStr1)
_replaceRecur1(tree, str2, newStr2)
callback(null, tree)
}
答案 2 :(得分:1)
不确定是否使用数组或字符串
使用数组,您可能想要替换多个内容。你不会改变replaceRecur
,它就好了。而是引入一个新功能
function replaceMultipleRecur(tree, strArr, newStrArr) {
… // (in the simplest occasion a loop over the arrays with calls to replaceRecur)
}
function replaceQuotes(tree) {
return replaceMultipeRecur([/"(?=\b)/g, /"(?!\b)/g], ['“', '”']);
}
我不想重复replaceRecur,str和newStr两次
您可以通过传递匹配所有案例的正则表达式和replacer callback而不是字符串来简单地使用您的exsting函数。
function replaceQuotes(tree) {
replaceRecur(tree, /("\b)|("\B)/g, function(m, l, r) {
return l ? '“' : '”';
});
return tree
}
答案 3 :(得分:1)
如果您想更多地抽象代码,可以采用以下方法:
function maprec(x, callback) {
return x.map ? x.map(function(x) {
return maprec(x, callback);
}) : callback(x);
}
function pipe() {
var fns = arguments;
return function(x) {
return [].reduce.call(fns, function(a, f) { return f(a) }, x);
}
}
// test/demo:
tree = ['foo "bar" !', ['baz', ['ccc "hi" ', 'd']], 'eee', ['"foo?"']];
converted = maprec(tree, pipe(
function(x) { return x.replace(/"(?=\b)/g, '{') },
function(x) { return x.replace(/"(?=\B)/g, '}') }
));
document.write("<pre>" + JSON.stringify(converted));
&#13;
好的,我们在这做了什么?首先,我们定义maprec
,一个递归映射器,它与map
相同,但尊重嵌套结构。第二个实用程序pipe
是函数编写器,它接受一堆函数并返回一个新函数,按顺序将这些函数应用于参数,类似于grep | sort | uniq
之类的unix管道(由此得名)。请注意,这与通常的compose
不同,后者是右关联的。最后,我们使用maprec(tree, pipe(replacer1, replacer2))
来完成实际工作。
(我使用{}
而不是花哨的引号使它们在控制台窗口中看起来更明显。)
为了说明流水线的力量,这是一个更高级的例子:
fancyQuotes = pipe(
function(x) { return x.replace(/"(?=\b)/g, '«') },
function(x) { return x.replace(/"(?=\B)/g, '»') }
);
trim = "".trim.call.bind("".trim);
wrap = function(x) { return this.replace(/\$/g, x)};
wrap.in = wrap.bind;
converted = maprec(tree, pipe(
fancyQuotes,
trim,
wrap.in("<p>$</p>")));
答案 4 :(得分:0)
前言:我和Bergi在一起comment above,只是两次调用函数并不意味着你在重复自己。将复杂性添加到一个简单的函数以避免调用它不一定是个好主意。
但是对于你的问题:你可以在函数中添加两个参数,如果没有给出则忽略它们:
function replaceRecur(tree, str1, newStr1, str2, newStr2) {
for (var i = 1; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
replaceRecur(tree[i], str1, newStr1, str2, newStr2);
} else {
tree[i] = tree[i].replace(str1, newStr1);
if (typeof str2 !== "undefined") {
tree[i] = tree[i].replace(str2, newStr2);
}
}
}
}
事实上,你可以通过循环无休止地继续这样做。
function replaceRecur(tree, str, newStr/*, str2, newStr2, ...*/) {
for (var i = 1; i < tree.length; i++) {
if (Array.isArray(tree[i])) {
replaceRecur.apply(this, arguments);
} else {
for (var arg = 1; arg + 1 < arguments.length; arg += 2) {
tree[i] = tree[i].replace(arguments[arg], arguments[arg + 1]);
}
}
}
}
请注意,在使用arguments
伪阵列的某些JavaScript引擎上,会对性能产生负面影响。在现代引擎上它根本不重要。
用法:
replaceRecur(tree, /"(?=\b)/g, '“', /"(?!\b)/g, '”');
答案 5 :(得分:0)
只需更改else
即可在数组中应用每个正则表达式。
else {
//array is the array of regex's passed
array.forEach(function(item) {
tree[i] = tree[i].replace(item, newStr);
});
}