【问题标题】:Solving alphabetical expression to obtain sentences using Binary Tree使用二叉树解决字母表达式以获得句子
【发布时间】:2019-09-06 13:11:17
【问题描述】:

我正在尝试解决字母表达式以获得有效的句子。

输入和输出的例子是:-

输入

实际:

(((​"​one​"​ . ​"​two​"​) | ​"​twelve​"​) . (​"​zero​"​ | ​"​o​"​) . ​"​six​"​)

代币化:

['(', '(', '(', 'one', '.', 'two', ')', '|', 'twelve', ')', '.', 
 '(', 'zero', '|', 'o', ')', '.', 'six', ')']

输出

  • 一二零六

  • 一二六

  • 十二点六

运营商

  • () - 必需分组运算符
  • [] - 可选分组运算符
  • . - 连接连接运算符
  • | - OR 连接运算符

. 运算符的优先级确实高于 | 运算符。 我无法理解我应该如何去做。 (我想用 Python 写代码)

【问题讨论】:

  • 在您的输入中,每个双引号都被zero-width spaces 包围。这是故意的吗?
  • 您需要编写一个分词器和一个(可能是递归下降)解析器。 SO 问题太宽泛了。
  • 我想“十二零六”也是一个可能的结果。

标签: algorithm data-structures binary-tree binary-search-tree graph-algorithm


【解决方案1】:

我假设您已经设法标记化输入。然后我会建议作为第二步从令牌构建一棵树,以便以下输入:

(((​"​one​"​ . ​"​two​"​) | ​"​twelve​"​) . (​"​zero​"​ | ​"​o​"​) . ​"​six​"​)

...将变成以下树:

请注意,您可以重新使用 OR 运算符和 None 元素(不会在最终字符串中产生任何内容)来实现可选词(包装在 [...] 中)。例如,["six"] 会被解释为(None|"six"),在树中是:

通过树,您可以使用递归来查找可能的字符串。每个递归调用都会返回一个可能的字符串列表(可能只有一个)。如果孩子属于. (AND) 操作,则为孩子找到的所有字符串列表必须组合为笛卡尔积。如果它们属于| (OR) 操作,则这些列表应该只是连接起来(因为任何子代的所有可能字符串都可能用于父代)。

这里有一些可能有用的代码:

import itertools
import re

# subclass list just to distinguish between arguments of a "." or "|" operator
class OrList(list): # for "|" operator arguments
    pass

class AndList(list): # for "." operator arguments
    pass

def parse(tokens):
    # helper function to conditionally either append-to or extend a list
    def add(lst, factor):
        if type(factor) == type(lst):
            lst.extend(factor)
        else:
            lst.append(factor)
        return lst

    # helper function to conditionally return the given list or its only element
    def simplify(lst):
        if isinstance(lst, OrList): # remove duplicates
            for i in range(len(lst)-1,-1,-1):
                if lst.index(lst[i]) < i:
                    del lst[i]
        return lst if len(lst) > 1 else lst[0]

    it = iter(tokens + [""])

    def recur(end):
        terms = OrList()
        factors = AndList()
        token = None
        while token != end:
            token = next(it)
            if token[0] == '"':
                add(factors, token[1:-1]) # remove the quotes
            elif token == "(":
                add(factors, recur(")"))
            elif token == "[": # encode [expr] as if it were: (|expr)
                add(factors, add(OrList([None]), recur("]")))
            else:
                raise ValueError("Expected expression, got {}".format(token))
            token = next(it)
            if token != end and token not in ".|":
                raise ValueError("Expected operator, got {}".format(token))
            if token == "|" or token == end:
                add(terms, simplify(factors))
                factors = AndList()
        return simplify(terms)

    return recur("")

def validPhrases(node): # returns list of strings
    if isinstance(node, list):
        results = [validPhrases(child) for child in node]
        if isinstance(node, OrList):
            # flatten
            results = list(itertools.chain.from_iterable(results))
        else: # instance of AndList
            # all combinations
            results = [" ".join([s for s in combi if s != None]) 
                    for combi in itertools.product(*results)]
        return list(set(results)) # remove duplicates
    else: # str
        return [node]

def generate(expr):
    # tokenize
    tokens = re.findall(r'"[^"]*"|\S', expr) # don't throw away the quotes yet
    # make a tree in line with precedence rules
    tree = parse(tokens)
    # finally build all possible strings from this tree
    return validPhrases(tree)

expr = '((("one" . "two" | "twelve") . ("zero" | "o")) . "six")'

print(generate(expr))

看到它在repl.it上运行

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    • 2015-11-18
    相关资源
    最近更新 更多