我正在寻找一种有效的方法(如:尽可能少的资源)用Javascript中的其他字符串替换字符串的orrurances。 重点是计算时间,而不是内存消耗。
搜索词和替换词作为用作词典的对象
var replacements = {
search : 'replace',
another : 'replacement',
'and one' : 'more'
}
目前我正在迭代密钥并构建一个正则表达式(带有set g标志),然后查找字典中的每个匹配并替换它:
String.prototype.mapReplace = function (map, replaceFullOnly = false) {
var regexp = [];
for (var key in map) {
regexp.push(RegExp.escape(key));
}
regexp = regexp.join('|');
if (replaceFullOnly) {
regexp = '\\b(?:' + regexp + ')\\b';
}
regexp = new RegExp(regexp, 'gi');
return this.replace(regexp, function (match) {
return map[match.toLowerCase()];
});
}
这很有效,但我每次都需要编译一个新的常规表达式。我的问题是:有人可以提出一种有效的方法来缓存常规表达式,如果是相同的映射(与“相同的键”相同,既不是“相同的对象”也不是“相同的值”,也不是“相同的键顺序”)再次给出正则expresiosn重新使用?
一种显而易见的方法是排序,序列化和散列密钥,将其用作存储常规表达式的密钥,并在将来调用时存在时重新使用存储的正则表达式。但是,我认为这很可能比每次编译一个新的常规表达需要更多的时间......
思想/输入?
编辑:RegExp.escape()是一个函数,用于转义字符串中的特殊字符以用于正则表达式:
RegExp.escape= function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};
使用信息:
答案 0 :(得分:0)
这就是我提出的:
var ReplacementMap = function (map, replaceFullOnly, ignoreCase) {
var regexp = null;
var update = function (search, replacement) {
if (!isDefined(replacement)) {
if (!(search in map)) return;
delete map[search];
} else {
if (map[search] == replacement) return;
map[search] = replacement;
}
invalidateRegexp();
}
var buildRegexp = function () {
if (regexp != null) return;
regexp = [];
for (var key in map) {
regexp.push(RegExp.escape(key));
}
regexp = regexp.join('|');
if (replaceFullOnly) {
regexp = '\\b(?:' + regexp + ')\\b';
}
regexp = new RegExp(regexp,'g' + (ignoreCase ? 'i' : ''));
}
var invalidateRegexp = function () {
regexp = null;
}
Object.defineProperties(this, {
fullOnly : {
set : value => {
if (replaceFullOnly == value) return;
replaceFullOnly = !!value;
invalidateRegexp();
},
get : () => replaceFullOnly
},
ignoreCase : {
set : value => {
if (ignoreCase == value) return;
ignoreCase = !!value;
invalidateRegexp();
},
get : () => ignoreCase
}
});
this.set = function set (search, replacement) {
if (Array.isArray(search)) {
if (Array.isArray(search[0])) {
search.forEach(function (search) {
set(search);
});
} else {
update(search[0], search.length > 1 ? search[1] : undefined);
}
} else if (search instanceof Object
&& search !== null
&& !String.isString(search)) {
for (key in search) {
update(key, search[key]);
}
} else update(search, replacement);
}
this.get = function (search) {
return search in map ? map[search] : undefined;
}
this.remove = function(search) {
update(search);
}
this.apply = function (string) {
buildRegexp();
return string.replace(regexp, function (match) {
return map[match.toLowerCase()];
});
}
this[Symbol.iterator] = function* () {
for (let key of Object.keys(map)) {
yield {[key] : map[key]};
}
return;
}
if (isDefined(replaceFullOnly)) {
replaceFullOnly = !!replaceFullOnly;
} else {
replaceFullOnly = true;
}
if (isDefined(ignoreCase)) {
ignoreCase = !!ignoreCase;
} else {
ignoreCase = true;
}
if (isDefined(map)) {
let entries = map;
map = Object.create(null);
this.set(entries);
} else {
map = Object.create(null);
}
}
用法:
// ---- CREATE MAP ----
// Empty Map
var m0 = new ReplacementMap();
// Map initialized with one replacement: foo => bar
var m1_1 = new ReplacementMap('foo','bar');
var m1_2 = new ReplacementMap(['foo','bar']);
var m1_3 = new ReplacementMap({foo : 'bar'});
// Map initialized with two replacements: foo => bar, fooz => baz
var m2_1 = new ReplacementMap([['foo','bar'], ['fooz', 'baz']]);
var m2_2 = new ReplacementMap({foo : 'bar', fooz : 'baz'});
var m2_3 = new ReplacementMap([{foo : 'bar'}, {fooz : 'baz'}]);
// ---- ADD/MODIFY ENTRIES ----
var m0.set(...) // ... parameters work the same as in the constructor
// ---- REMOVE ENTRIES ----
var m2_1.delete('foo') // removes replacement rule for foo => bar
var m2_1.delete('test') // fails silently
// ---- READ ENTRIES ----
var m2_1.get('foo') // returns "bar"
var m2_1.get('test') // returns undefined;
for (rule of m2_1) {
alert(JSON.stringify(rule));
}
// alerts "{'foo':'bar'}" and "{'fooz':'baz'}"
// ---- APPLY ON STRING ----
alert(m2_1.apply("foo bar")) // bar bar
// change behaviour:
m2_1.fullOnly = true; // replace foo with bar, but not foobar with barbar
// default: true;
m2_1.ignoreCase = true; // ignore case. default: true