Algorithm 如何从以特殊格式显示的单个字符串创建所有可能的变体?

Algorithm 如何从以特殊格式显示的单个字符串创建所有可能的变体?,algorithm,parsing,text,Algorithm,Parsing,Text,比方说,我有以下模板 Hello, {I'm|he is} a {notable|famous} person. 结果应该是 Hello, I'm a notable person. Hello, I'm a famous person. Hello, he is a notable person. Hello, he is a famous person. 我想到的唯一可能的解决方案是完全搜索,但它并不有效。 可能有一个很好的算法来做这样的工作,但我不知道是什么任务。数组中的所有置换都非常

比方说,我有以下模板

Hello, {I'm|he is} a {notable|famous} person.
结果应该是

Hello, I'm a notable person.
Hello, I'm a famous person.
Hello, he is a notable person.
Hello, he is a famous person.
我想到的唯一可能的解决方案是完全搜索,但它并不有效。 可能有一个很好的算法来做这样的工作,但我不知道是什么任务。数组中的所有置换都非常接近于此,但我不知道如何在这里使用它

这里是工作解决方案(它是对象的一部分,所以这里只是相关部分)

generateText()解析字符串并将
'Hello,{1 | 2},here{3,4}'
转换为
['Hello',['1','2'],'here',['3','4']]]

extractText()接受这个多维数组并创建所有可能的字符串

        STATE_TEXT: 'TEXT',
        STATE_INSIDE_BRACKETS: 'INSIDE_BRACKETS',

        generateText: function(text) {
            var result = [];
            var state = this.STATE_TEXT;
            var length = text.length;
            var simpleText = '';
            var options = [];
            var singleOption = '';
            var i = 0;

            while (i < length) {
                var symbol = text[i];

                switch(symbol) {
                    case '{':
                        if (state === this.STATE_TEXT) {
                            simpleText = simpleText.trim();
                            if (simpleText.length) {
                                result.push(simpleText);
                                simpleText = '';
                            }
                            state = this.STATE_INSIDE_BRACKETS;
                        }
                        break;
                    case '}':
                        if (state === this.STATE_INSIDE_BRACKETS) {
                            singleOption = singleOption.trim();
                            if (singleOption.length) {
                                options.push(singleOption);
                                singleOption = '';
                            }
                            if (options.length) {
                                result.push(options);
                                options = [];
                            }
                            state = this.STATE_TEXT;
                        }
                        break;
                    case '|':
                        if (state === this.STATE_INSIDE_BRACKETS) {
                            singleOption = singleOption.trim();
                            if (singleOption.length) {
                                options.push(singleOption);
                                singleOption = '';
                            }
                        }
                        break;
                    default:
                        if (state === this.STATE_TEXT) {
                            simpleText += symbol;
                        } else if (state === this.STATE_INSIDE_BRACKETS) {
                            singleOption += symbol;
                        }
                        break;
                }

                i++;
            }

            return result;
        },

        extractStrings(generated) {
            var lengths = {};
            var currents = {};
            var permutations = 0;
            var length = generated.length;
            for (var i = 0; i < length; i++) {
                if ($.isArray(generated[i])) {
                    lengths[i] = generated[i].length;
                    currents[i] = lengths[i];
                    permutations += lengths[i];
                }
            }

            var strings = [];

            for (var i = 0; i < permutations; i++) {
                var string = [];
                for (var k = 0; k < length; k++) {
                    if (typeof lengths[k] === 'undefined') {
                        string.push(generated[k]);
                        continue;
                    }

                    currents[k] -= 1;
                    if (currents[k] < 0) {
                        currents[k] = lengths[k] - 1;
                    }
                    string.push(generated[k][currents[k]]);
                }

                strings.push(string.join(' '));
            }

            return strings;
        },
STATE_TEXT:“TEXT”,
在括号内注明:“括号内”,
generateText:函数(文本){
var结果=[];
var state=this.state\u TEXT;
var length=text.length;
var simpleText='';
var期权=[];
var singleOption='';
var i=0;
while(i
这里的最佳解决方案似乎是
n*m
,其中
n=第一个数组
m=第二个数组
。有nm所需的输出线,这意味着只要你只做nm,你就不会做任何额外的工作

如果有2个以上带有选项的数组,则此操作的一般运行时间为

n1*n2…*nm,其中每一个都等于相应列表的大小

一个嵌套循环,您只需打印出外部循环的当前索引值和内部循环的当前索引值,就可以正确地执行此操作

我想到的唯一可能的解决方案是完全搜索,但它并不有效

如果必须提供完整结果,则必须运行完整搜索。根本没有办法解决这个问题。不过,您不需要所有排列:结果的数量等于每个模板中备选方案数量的乘积

Hello, {I'm|he is} a {notable|famous} person.
尽管有多种实现方法,但递归是最流行的方法之一。下面是一些让您开始使用的伪代码:

string[][] templates = {{"I'm", "he is"}, {"notable", "famous", "boring"}}
int[] pos = new int[templates.Length]
string[] fills = new string[templates.Length]
recurse(templates, fills, 0)
...
void recurse(string[][] templates, string[] fills, int pos) {
    if (pos == fills.Length) {
        formatResult(fills);
    } else {
        foreach option in templates[pos] {
            fills[pos] = option
            recurse(templates, fills, pos+1);
        } 
    }
}

这取决于具体的用例。这些模板是预定义的还是以某种方式受到限制的。您是只搜索一个“小”文本,还是有多个文本单元可供搜索。这些文本经常变化还是很少变化……。可以有许多行,每行可以有数千个{a | b | c}模板(以及其他一些shell)内置rhis功能,尽管您需要使用
而不是
|
来分离备选方案,并且还需要一些引用。例如,尝试使用
printf“%s\n””你好,“{”我“,”他“}”是一个“{著名的}”人。