【问题标题】:How to parse a string and return a nested array?如何解析字符串并返回嵌套数组?
【发布时间】:2013-06-13 00:19:03
【问题描述】:

我想要一个 Python 函数,它接受一个字符串并返回一个数组,其中数组中的每个项目要么是一个字符,要么是另一个此类数组。嵌套数组在输入字符串中以 '(' 开头并以 ')' 结尾进行标记。

因此,函数的行为如下:

1) foo("abc") == ["a", "b", "c"]
2) foo("a(b)c") == ["a", ["b"], "c"]
3) foo("a(b(c))") == ["a", ["b", ["c"]]]
4) foo("a(b(c)") == error: closing bracket is missing
5) foo("a(b))c") == error: opening bracket is missing
6) foo("a)b(c") == error: opening bracket is missing

注意:我更喜欢纯功能性的解决方案。

【问题讨论】:

  • 在这里使用递归,非常合适。在令牌流中找到“(”意味着递归。在顶级调用中找到“)”意味着存在平衡不匹配。
  • 确实是递归。只要字符串不太长,就是这样。还请记住,这可能需要一个包装函数,因为我们需要检查 '(' 的数量是否与 ')' 的数量匹配。如果是这样,请调用递归函数。如果不是,请给出适当的错误消息。
  • 是的,我知道我会在这里使用递归。我知道如何编写一个函数(使用堆栈)来返回字符串中的括号是否平衡且有序,但它正在采取下一步并试图返回让我难过的嵌套数组。这不是家庭作业。这是一个更大的解析程序的一部分。

标签: python arrays string parsing nested


【解决方案1】:
def foo(s):
    def foo_helper(level=0):
        try:
            token = next(tokens)
        except StopIteration:
            if level != 0:
                raise Exception('missing closing paren')
            else:
                return []
        if token == ')':
            if level == 0:
                raise Exception('missing opening paren')
            else:
                return []
        elif token == '(':
            return [foo_helper(level+1)] + foo_helper(level)
        else:
            return [token] + foo_helper(level)
    tokens = iter(s)
    return foo_helper()

还有,

>>> foo('a((b(c))d)(e)')
['a', [['b', ['c']], 'd'], ['e']]

【讨论】:

  • 你想尝试用函数式风格重写这个吗?
  • @FinalZero 你是什么意思?这已经是一个递归解决方案了。
  • 我的意思是不使用iternext
  • 答案不是纯函数式的,但无论如何我都会接受它,因为它帮助我概念化和编写纯函数式解决方案,这需要foo 返回一个元组而不仅仅是一个数组.
【解决方案2】:

迭代。

def foo(xs):
    stack = [[]]
    for x in xs:
        if x == '(':
            stack[-1].append([])
            stack.append(stack[-1][-1])
        elif x == ')':
            stack.pop()
            if not stack:
                return 'error: opening bracket is missing'
                #raise ValueError('error: opening bracket is missing')
        else:
            stack[-1].append(x)
    if len(stack) > 1:
        return 'error: closing bracket is missing'
        #raise ValueError('error: closing bracket is missing')
    return stack.pop()

assert foo("abc") == ["a", "b", "c"]
assert foo("a(b)c") == ["a", ["b"], "c"]
assert foo("a(b(c))") == ["a", ["b", ["c"]]]
assert foo("a((b(c))d)(e)") == ['a', [['b', ['c']], 'd'], ['e']]
assert foo("a(b(c)") == "error: closing bracket is missing"
assert foo("a(b))c") == "error: opening bracket is missing"
assert foo("a)b(c") == 'error: opening bracket is missing'

【讨论】:

  • +1 你不需要result:只需设置stack = [[]],然后返回stack.pop()。这样看起来更纯粹——只是堆栈。
【解决方案3】:

我建议两种方法:

要么编写你自己的递归下降解析器,比如here,要么使用pyparsing,比如

import pyparsing as pp
expr = pp.Forward()
expr << pp.Word(pp.alphas) + pp.Optional('(' + expr + ')') + pp.Optional(pp.Word(pp.alphas))

在这里,您将递归表达式描述为一系列 alpha,可以通过平衡括号进行交错。当您检查此示例的输出时,您将看到如何获得所需的输出结构(尽管这需要您进行一些调整并需要了解一些有关 pyparsing 的知识)。

问候 标记

【讨论】:

    【解决方案4】:

    使用regexast.literal_eval

    >>> import re
    >>> from ast import literal_eval
    >>> def listit(t):
    ...         return list(map(listit, t)) if isinstance(t, (list, tuple)) else t
    ... 
    def solve(strs):
        s = re.sub(r'[A-Za-z]', "'\g<0>',", strs)
        s = re.sub(r"\)", "\g<0>,", s)
        try: return listit( literal_eval('[' + s  + ']') )
        except : return "Invalid string! "
    ...     
    >>> solve("abc")
    ['a', 'b', 'c']
    >>> solve("a(b)c")
    ['a', ['b'], 'c']
    >>> solve("a(b(c))")
    ['a', ['b', ['c']]]
    >>> solve("a(b(c)")
    'Invalid string! '
    >>> solve("a)b(c")
    'Invalid string! '
    >>> solve("a(b))c")
    'Invalid string! '
    >>> solve('a((b(c))d)(e)')
    ['a', [['b', ['c']], 'd'], ['e']]
    

    【讨论】:

      【解决方案5】:

      一种相当快速和讨厌的方法(只是为了不同的东西):

      import json, re
      
      def foo(x):
          # Split continuous strings
          # Match consecutive characters
          matches = re.findall('[a-z]{2,}', x)
          for m in matches:
              # Join with ","
              x = x.replace(m, '","'.join(y for y in list(m))) 
      
          # Turn curvy brackets into square brackets
          x = x.replace(')', '"],"')
          x = x.replace('(', '",["')
      
          # Wrap whole string with square brackets
          x = '["'+x+'"]'
      
          # Remove empty entries
          x = x.replace('"",', '')
          x = x.replace(',""', '')
      
          try:
              # Load with JSON
              return json.loads(x)
          except:
              # TODO determine error type
              return "error"
      
      def main():
          print foo("abc")     # ['a', 'b', 'c']
          print foo("a(b)c")   # ['a', ['b'], 'c']
          print foo("a(b(c))") # ['a', ['b', ['c']]]
          print foo("a(b))c")  # error
      
          print foo('a((b(c))d)(e)') # ['a', [['b', ['c']], 'd'], ['e']]
      

      【讨论】:

        【解决方案6】:
        def parse_nested(iterator, level=0):
            result = []
            for c in iterator:
                if c == '(':
                    result.append(parse_nested(iterator, level+1))
                elif c == ')':
                    if level:
                        return result
                    else:
                        raise ValueError("Opening parenthesis missing")
                else:
                    result.append(c)
            if level:
                raise ValueError("Closing parenthesis missing")
            else:
                return result
        
        print parse_nested(iter('a((b(c))d)(e)'))       
        

        【讨论】:

          【解决方案7】:

          递归是非常强大的东西,你应该尝试使用它。

          这是我的代码:

          
          
              # encoding: utf-8
              # Python33
          
              def check(s):
                  cs = [c for c in s if c == '(' or c ==')']
                  flag = 0
                  for c in cs:
                      if flag < 0:
                          return 'opening bracket is missing'        
                      if c == '(':
                          flag += 1
                      else:
                          flag -= 1
                  if flag < 0:
                      return 'opening bracket is missing'
                  elif flag > 0:
                      return 'closing bracket is missing'
                  else:
                      return ''
          
              def _foo(cs):
                  result = []
                  while len(cs):
                      c = cs.pop(0)
                      if c == '(':
                          result.append(_foo(cs))
                      elif c == ')':
                          return result
                      else:
                          result.append(c)
                  return result
          
              def foo(s):
                  valiad = check(s)
                  if valiad:
                      return valiad
                  cs = list(s)
                  return _foo(cs)
          
              if __name__ == '__main__':
                  ss = ["abc","a(b)c","a(b(c))","a(b(c)","a(b))c","a)b(c"]
                  for s in ss:
                      print(foo(s))
          
          

          【讨论】:

          • 我的代码没问题,但在答案区域显示时出错...我正在尝试修复它。_______我替换了 '
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-12-09
          • 1970-01-01
          相关资源
          最近更新 更多