如何在JavaScript中生成单词中字符替换的所有可能组合?

时间:2017-06-27 11:22:21

标签: javascript regex algorithm array-algorithms

考虑下面这个词:" zazaza"。

我试图提出一个函数,给出一个替换字母和一个与该字母匹配的单词,生成该字母替换的所有组合。

我有一个JSON,其中包含要匹配的字母和要替换的字母,如下所示:

var replacement = {original: 'Z', replace: 'S'};

完整的例子是这样的:

var generatedCombinations = generateAllCombinations(replacement, "zazaza");

数组将包含:

zazaza
sazaza
sasaza
sasasa
zasasa
zazasa
...

这听起来像使用递归更容易实现,但据我所知,JavaScript中的函数调用可能很昂贵,所以我不确定采用这种方法。我认为我的主要问题是如何确保我生成所有组合。

创建这个数组的目的是让我可以将所有这些单词与另一个单词匹配,所以我不确定是否有正则表达式可以做到这一点并且实现起来更实用。< / p>

1 个答案:

答案 0 :(得分:1)

有N个可能的位置来插入替换字母,您的任务归结为生成一组位置的所有可能子集。这可以通过从0迭代到2 ^ N来完成,其中每次迭代发出包含与循环计数器的设置位相对应的元素的子集。

这非常有效,但由于javascript限制,仅适用于最多32个元素。

在一般情况下,递归是要走的路,例如:

let powerset = a => _powerset([[]], a);

let _powerset = (out, rest) =>
    rest.length ?
        _powerset(
            out.concat(out.map(x => x.concat(rest[0]))),
            rest.slice(1))
        : out;

请注意,此函数是尾递归的,因此现代JS引擎将能够优化函数调用。

(无聊等待V8编译,所以这里是完整的代码);)

let powerset = a => _powerset([[]], a);

let _powerset = (out, rest) =>
    rest.length ?
        _powerset(
            out.concat(out.map(x => x.concat(rest[0]))),
            rest.slice(1))
        : out;

let enumerate = (str, char) => [...str]
    .map((c, i) => [c, i])
    .filter(p => p[0] === char)
    .map(p => p[1]);

let translate = (str, pos, replace) => [...str]
    .map((c, i) => pos.includes(i) ? replace : c) // @todo: optimize me
    .join('');


let allReplacements = (str, char, replace) =>
    powerset(enumerate(str, char)).map(pos => translate(str, pos, replace));


console.log(allReplacements('_abc_def_x', '_', '@'));