根据我的研究,正则表达式replace
不是异步的。因此,对于为什么do-while
循环中的匹配和替换有时无法匹配,我有些困惑。
我在下面创建了一个代码段,如果值中有任何匹配项,可以选择对其进行“双重检查”,但是我不知道为什么双重检查实际上阻止了它忽略匹配项。
您将在控制台中看到,injectableRegex.exec()
在do-while
循环中运行两次后,它将正确替换所有匹配项。
更新:即使此方法也不一致,因为我发现有时doubleCheck部分正确匹配,然后随后的exec
调用失败
const getInjectedPhrase = (phrase, injections, doubleCheck) => {
let value = phrase;
// only need to attempt to replace the injectables in the phrase is we've been passed injections
if (injections && phrase.length > 1) {
const injectableRegex = /{{\s?([\w-]+)\s?}}/g; // find any matching injectable, and extract its key
let match;
window.console.log('initial phrase:', phrase);
// check if dictionary value contains injectable sections ie. sections surrounded by {{ }}
do {
// WHY IS THIS A THING!?
if (doubleCheck) {
injectableRegex.exec(value)
}
match = injectableRegex.exec(value);
if (match) {
/*
match[0] -> {{ x }}
match[1] -> x
*/
const injectionValue = injections[match[1]];
const injectionValueType = typeof injectionValue;
if (
injectionValueType === "string" ||
injectionValueType === "number"
) {
// globally replace the value with the injection's value
value = value.replace(new RegExp(match[0], "g"), `${injectionValue}`);
window.console.log('partial replace phrase:', value);
}
}
} while (match !== null);
}
window.console.log('returned phrase:', value);
return value;
};
window.console.log('WITHOUT DOUBLE CHECKING');
getInjectedPhrase(
"foo {{partialCount}} of {{count}} bars", {
partialCount: 3,
count: 4
},
false
);
window.console.log('USING DOUBLE CHECKING');
getInjectedPhrase(
"foo {{partialCount}} of {{count}} bars", {
partialCount: 3,
count: 4
},
true
);
答案 0 :(得分:1)
问题在于正则表达式保留lastIndex
属性,该属性跟踪最后一个匹配项的结束索引。在
foo {{partialCount}} of {{count}} bars
匹配
{{partialCount}}
随后将lastIndex
属性设置为20
-第二个}
之后的位置。
然后,当您重新分配字符串以
foo 3 of {{count}} bars
使用相同的正则表达式尝试匹配将在该字符串的索引20 处开始,该字符串为{em> past {{count}}
部分,因此匹配失败。
一种选择是每次将lastIndex
手动重置为0:
const getInjectedPhrase = (phrase, injections, doubleCheck) => {
let value = phrase;
// only need to attempt to replace the injectables in the phrase is we've been passed injections
if (injections && phrase.length > 1) {
const injectableRegex = /{{\s?([\w-]+)\s?}}/g; // find any matching injectable, and extract its key
let match;
window.console.log('initial phrase:', phrase);
// check if dictionary value contains injectable sections ie. sections surrounded by {{ }}
do {
injectableRegex.lastIndex = 0;
match = injectableRegex.exec(value);
if (match) {
/*
match[0] -> {{ x }}
match[1] -> x
*/
const injectionValue = injections[match[1]];
const injectionValueType = typeof injectionValue;
if (
injectionValueType === "string" ||
injectionValueType === "number"
) {
// globally replace the value with the injection's value
value = value.replace(new RegExp(match[0], "g"), `${injectionValue}`);
window.console.log('partial replace phrase:', value);
}
}
} while (match !== null);
}
window.console.log('returned phrase:', value);
return value;
};
window.console.log('WITHOUT DOUBLE CHECKING');
getInjectedPhrase(
"foo {{partialCount}} of {{count}} bars", {
partialCount: 3,
count: 4
},
false
);
一个更好的选择是使用回调函数一次replace
,而无需手动迭代,替换和重置正则表达式对象:
const getInjectedPhrase = (str, obj) => str.replace(
/{{\s?([\w-]+)\s?}}/g,
(_, key) => obj[key]
);
console.log(
getInjectedPhrase(
"foo {{partialCount}} of {{count}} bars", {
partialCount: 3,
count: 4
},
)
);