找到所有“字符相等”字符串的高效算法?

我们如何编写一个输出输入字符串“ homoglyph equivalent ”的高效函数?

例1 (伪代码):

homoglyphs_list = [ ["o", "0"], // "o" and "0" are homoglyphs ["i", "l", "1"] // "i" and "l" and "1" are homoglyphs ] input_string = "someinput" output = [ "someinput", "s0meinput", "somelnput", "s0melnput", "some1nput", "s0me1nput" ] 

例2

 homoglyphs_list = [ ["rn", "m", "nn"], ] input_string = "rnn" output = ["rnn", "rm", "mn", "rrn", "nnn", "nm", "nrn"] 

例3

 homoglyphs_list = [ ["d", "ci", "a"], // "o" and "0" are homoglyphs ["i", "l", "1"] // "i" and "l" and "1" are homoglyphs ] /* notice that with the two rules above, we can infer "d" = "ci" = "a" = "cl" = "c1" */ input_string = "pacerier" output = [ "pacerier", "pacerler", "pacer1er", "pcicerier", "pcicerler", "pcicer1er", "pclcerier", "pc1cerier", "pclcerler", "pc1cerler", "pclcer1er", "pc1cer1er", "pdcerier", "pdcerler", "pdcer1er" ] 

注意:输出数组中成员的顺序并不重要,我们可以假设给定的同形字映射是正确的 (输入不会给我们一个“无限循环”)。

我当前的算法有效,但它使用原始强制执行并且性能很糟糕。 例如,带有同形字符["rn", "m", "nn"]"mmmmm"输入需要38秒才能运行:

 // This is php code (non-pseudo just so we could test the running time), // but the question remains language-agnostic public function Func($in, Array $mappings){ $out_table = array(); $out_table[$in] = null; while(true){ $number_of_entries_so_far = count($out_table); foreach(array_keys($out_table) as $key){ foreach($mappings as $mapping){ foreach($mapping as $value){ for($a=0, $aa=strlen($key); $a<$aa; ++$a){ $pos = strpos($key, $value, $a); if($pos === false){ continue; } foreach($mapping as $equal_value){ if($value === $equal_value){ continue; } $out_table[substr($key, 0, $pos) . $equal_value . substr($key, $pos + strlen($value))] = null; } } } } } if($number_of_entries_so_far === count($out_table)){ // it means we have tried bruteforcing but added no additional entries, // so we can quit now break; } } return array_keys($out_table); } 

我们如何实现高效(快速)同形文字扩展算法?

你应该从递归实现中获得一些性能,但我并没有考虑实际的性能。 这将避免多次循环输出字符串并每次迭代计算输出。 此外,我添加了一个“缓存”以防止计算两次相同的同性字,为简单起见它不会检查映射,但你可以实现它,或者只是在每次调用映射改变之前清除缓存(但那是丑陋,容易引入错误)。

代码如下:

 cache = {} def homoglyph(input_string, mappings): output = [] character = input_string[0] if input_string in cache: return cache[input_string] elif not input_string: return [] for charset in mappings: if character in charset: temp = input_string sub_homoglyphs = homoglyph(input_string[1:], mappings) for char in charset: temp[0] = char output.append(temp) #adding the homoglyph character to the rest of the string for subhomoglyph in sub_homoglyphs: output.append(char+subhomoglyph) cache[input_string] = output return output 

(这是用python编写的,因为我不熟悉php语法,我实际上没有运行它,所以可能有错误,但逻辑的要点就在那里)