【问题标题】:Calculating all possibilities for a string with optional parts计算带有可选部分的字符串的所有可能性
【发布时间】:2019-10-13 20:51:58
【问题描述】:

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

  • A[B]AAB
  • A[B][C]A, AB, ACABC
  • A[B[C]]AABABC

我希望这足以解释我想要做什么。

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

我的预感是否正确,实际上是否有一种现有的(有据可查的)方法来解决这个问题?

【问题讨论】:

  • 不知道现有的算法,但如果我必须这样做,我会为模式构建图,将图扩展为树,然后进行广度优先遍历。
  • “算法”和“算法”有什么区别? (意思是,你为什么在问题描述中把这个词放在引号中)
  • @גלעדברקן 好点,我使用“算法”(带引号)的意思是:它符合算法的定义,但它不是“以任何方式“聪明”或“高效”。这更有意义吗?
  • @NeilEdelman 看起来确实很相似,但我不确定如何将其应用于我的问题。你能详细说明一下吗?

标签: string algorithm combinatorics


【解决方案1】:

我没有读过这篇文章,但似乎已经研究过这个问题。 117页有一篇文章:《Enumeration of Formal Languages》http://www.eatcs.org/images/bulletin/beatcs89.pdf

您可以通过搜索“为 DFA 枚举语言”等良好关键字搜索来找到更多关于此主题的信息

【讨论】:

    【解决方案2】:

    您定义的语法仅包含 2 个不同的实体:终端(一个字符)或语法的可选部分。

    在下面的 Haskell 代码中,这反映在可区分联合 Grammar 的定义中。

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

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

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

    • 如果在给定位置的语法列表中找到终结符号,则将相应字符粘贴到从语法列表的其余部分生成的所有变体前面。

    • 如果在语法列表中找到可选部分,则生成语法列表其余部分的列表两次;一次带有可选部分,一次没有。

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

    data Grammar = Terminal Char | Optional [Grammar] deriving (Show,Eq)
    
    fromString :: String -> [Grammar] -> ([Grammar],String)
    fromString [] acc = (acc,"")
    fromString ('[':cs) acc = 
        let (o,rest) = fromString cs [] in
            fromString rest (acc ++ [Optional o])
    fromString (']':cs) acc = (acc,cs)
    fromString (c:cs) acc = fromString cs (acc ++ [Terminal c])
    
    generate :: [Grammar] -> [String]
    generate [] = [""]
    generate ((Terminal c) : parts) = fmap (\s -> c : s) $ generate parts
    generate ((Optional gs) : parts) = tails ++ (concat . fmap prependOpts $ tails)
        where 
            tails = generate parts
            opts = generate gs
            prependOpts :: String -> [String]
            prependOpts tail = fmap (\o -> o ++ tail) $ opts
    

    将所有内容放在 REPL(交互式 shell)中,运行 fromString "A[B][C]" [],例如:
    ([Terminal 'A',Optional [Terminal 'B'],Optional [Terminal 'C']],"")

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

    【讨论】:

    • 这看起来很有趣,但不幸的是我根本不了解 Haskell,所以我不能 100% 确定我理解你的概念(因为我几乎看不懂你的代码)。明天我会尝试再看看这个,看看我是否能破译这个功能混乱。
    【解决方案3】:

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

    function f(string, index, combinations){
      if (index == string.length)
        return [combinations, index]
        
      if (string[index] == "["){
        let prefixes = []
        let [suffixes, nextIndex] = f(string, index + 1, [""])
    
        for (let combination of combinations)
          for (let suffix of suffixes)
            prefixes.push(combination + suffix)
    
        if (nextIndex == string.length)
          return [combinations.concat(prefixes), nextIndex]
        else
          return f(string, nextIndex, combinations.concat(prefixes))
        
      } else if (string[index] == "]"){
        return [combinations, index + 1]
        
      } else {
        for (let i=0; i<combinations.length; i++)
          combinations[i] += string[index]
        return f(string, index + 1, combinations)
      }
    }
    
    strings = [
      "A[B]",
      "A[B][C]",
      "A[B[C]]"
    ]
    
    for (let string of strings)
      console.log(JSON.stringify(f(string, 0, [""])[0]))

    【讨论】:

      【解决方案4】:

      算法可能如下:

      - 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.
      

      您还可以使用下推自动机来解析字符串,以了解括号在哪里打开和在哪里关闭。您可以找到许多案例的实现。

      【讨论】:

      • 这种方法与我自己想出的方法非常相似。生成树的有效方法是什么?
      • @superbadcodemonkey 您可以使用下推自动机来解析字符串,以了解括号在哪里打开和在哪里关闭。您可以找到许多案例的实现。
      猜你喜欢
      • 1970-01-01
      • 2020-06-03
      • 1970-01-01
      • 1970-01-01
      • 2018-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      相关资源
      最近更新 更多