String 计算具有可选部分的字符串的所有可能性

String 计算具有可选部分的字符串的所有可能性,string,algorithm,combinatorics,String,Algorithm,Combinatorics,我想生成一个包含可选部分的字符串的所有可能组合的列表。这可能最好用一些例子来解释: A[B]→ A和AB A[B][C]→ A,AB,AC和ABC A[B[C]→ A,AB和ABC 我希望这能充分解释我要做的事情 我可以用我自己的小解析器或“算法”来解决这个问题,但我有一种强烈的感觉,就是有一个现成的(更简单的)解决方案。因为我还没有接受过任何CS教育,所以我不知道我在寻找什么样的算法,甚至不知道使用什么搜索词 我的预感正确吗?是否真的有一个现成的(有充分证明的)方法来解决这个问题?我没有读

我想生成一个包含可选部分的字符串的所有可能组合的列表。这可能最好用一些例子来解释:

  • A[B]
    → <代码>A和
    AB
  • A[B][C]
    → <代码>A,
    AB
    AC
    ABC
  • A[B[C]
    → <代码>A,
    AB
    ABC
我希望这能充分解释我要做的事情

我可以用我自己的小解析器或“算法”来解决这个问题,但我有一种强烈的感觉,就是有一个现成的(更简单的)解决方案。因为我还没有接受过任何CS教育,所以我不知道我在寻找什么样的算法,甚至不知道使用什么搜索词


我的预感正确吗?是否真的有一个现成的(有充分证明的)方法来解决这个问题?

我没有读过这篇文章,但似乎这个问题已经被研究过了。第117页有一篇文章:“形式语言枚举”


通过使用诸如“enumerate language for DFA”之类的好关键字进行搜索,您可以找到有关此主题的更多信息。算法可能如下所示:

- Parse the string and make a rooted binary tree that on each node breaks on 
the new bracket exists or not.

- You can go through the root to the leaf of the tree.
  All paths from the root to leaves generate all combinations.

此外,您还可以使用下推自动机来解析字符串,以了解括号的打开位置和关闭位置。对于这种情况,您可以找到许多实现。

以下是JavaScript中的一些内容,仅针对提供的三个示例进行了测试。希望从代码中可以清楚地看到(尝试的)重复:

函数f(字符串、索引、组合){ if(index==string.length) 返回[组合,索引] 如果(字符串[索引]=“[”){ 让前缀=[] 让[后缀,nextIndex]=f(字符串,索引+1,[“”]) for(让组合的组合) for(设后缀的后缀) 前缀.push(组合+后缀) if(nextIndex==string.length) return[combines.concat(前缀),nextIndex] 其他的 返回f(字符串、nextIndex、combines.concat(前缀)) }else if(字符串[索引]=“]”){ 返回[组合,索引+1] }否则{
对于(设i=0;i),您定义的语法只包含两个不同的实体:终端(字符)或语法的可选部分

在下面的Haskell代码中,这一点可以通过区分联合
语法
的定义反映出来

第一个任务是将给定的具体语法(例如“a[B]”)转换为语法部分列表(每个终端或可选)。在下面的代码中,函数
fromString
就是这样做的

不过,有趣的部分是如何为给定语法生成所有可能的字符串。 在下面的代码中,函数
generate
递归地执行此操作

  • 对于空语法列表(递归结束),输出是一个空字符串

  • 如果在给定位置的语法列表中找到一个终端符号,则相应的字符将粘贴在所有变体之前,这些变体是由语法列表的其余部分生成的

  • 如果在语法列表中找到可选部分,则语法列表其余部分的列表将生成两次;一次是在可选部分前面加上前缀,一次是不加前缀

对于阅读本文的非功能人士,应该指出,
fmap
是一个将列表映射到另一个列表的函数(按元素)。 我在下面的代码中使用的另一个函数,非haskellers可能会遇到的问题是
concat
,它将列表列表转换为列表

data Grammar=Terminal Char |可选的[Grammar]派生(Show,Eq)
fromString::String->[Grammar]->([Grammar],String)
fromString[]acc=(acc,“”)
fromString('[':cs)acc=
let(o,rest)=fromString cs[]in
fromString rest(acc++[可选o])
fromString(']':cs)acc=(acc,cs)
fromString(c:cs)acc=fromString cs(acc++[终端c])
生成::[语法]->[字符串]
生成[]=[“”]
生成((终端c):零件)=fmap(\s->c:s)$生成零件
生成((可选gs):零件)=tails++(concat.fmap preponets$tails)
哪里
尾部=生成零件
opts=生成gs
PREPOINTTS::字符串->[String]
preponets tail=fmap(\o->o++tail)$opts
将它们放在REPL(交互式shell)中,运行
fromString“A[B][C]”[]
,例如产生:
([Terminal'A',可选[Terminal'B',可选[Terminal'C']],”)

如果我们在上面的语法列表(元组的第一部分)上运行
generate
,我们将得到所有字符串:
生成(fst$fromString“A[B][C]”[])


[“A”、“AC”、“AB”、“ABC”]

不知道现有的算法,但如果必须这样做,我会为模式构建图形,将图形展开为树,然后进行广度优先遍历。我认为这是一个。算法和“算法”之间的区别是什么?(意思是,你为什么在问题描述中用引号引这个词?)@好的,我用了“算法”(带引号),意思是:它符合算法的定义,但不是“聪明”或“高效”无论如何。这更有意义吗?@NeilEdelman看起来很相似,但我不确定如何将其应用于我的问题。你能详细说明一下吗?这种方法与我自己想出的方法非常相似。生成树的有效方法是什么?@superbadcodemonkey你可以使用下推自动机来解析字符串用于了解括号的打开位置和关闭位置。您可以找到许多用于此情况的实现。这看起来很有趣,但不幸的是,我根本不认识Haskell,因此我不能100%确定我是否理解您的概念(因为我几乎看不懂您的代码)。我将尝试再看一看