使用 Python 将字符串标记为嵌套数组列表

Tokenizing a string into a list of nested arrays with Python

跟随 this document I'm writing an interpreter for Brainfuck,在我的实现中需要转换一个字符串,例如:

',>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.'

进入这样的指令列表:

[',', '>', ',', '<', [ '>', [ '-', '>', '+', '>', '+', '<', '<', ], '>', '>', [ '-', '<', '<', '+', '>', '>', ] '<', '<', '<', '-' ], '>', '>', '.']

或者,减去符号:

[ ... [...] ... [...] ... ]

现在我正在使用 deque 和 popleft() 递归地解决这个问题,一次迭代一个符号的字符串,但我觉得我应该一次将它分解成子数组。

你会如何用 Pythonic 的方式解决这个问题?

(出于速度原因排除正则表达式)

我快到了:

s=',>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.'

x = eval('["' + s.replace('[','",["').replace(']','"],"') + '"]')

这会产生:

[',>,<', ['>', ['->+>+<<'], '>>', ['-<<+>>'], '<<<-'], '>>.']

这不是您想要的,但您也可以遍历字符串。

如果您担心评估的安全性,请使用ast.literal_eval

更新: 使用正则表达式,我一路做到了:

import re
s=',>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.'
everything = re.compile("([^\]\[])")
y = eval('[' + everything.sub(r'"",',s).replace(",]","]").replace(']"','],"') + ']')

这变成:

[',', '>', ',', '<', ['>', ['-', '>', '+', '>', '+', '<', '<'], '>', '>', ['-', '<', '<', '+', '>', '>'], '<', '<', '<', '-'], '>', '>', '.']

它不完全是 "Pythonic way",但是....我找到了使用递归和生成器解决问题的方法

s = ',>,<[>[->+>+<<]>>[-<<+>>]<<<-]>>.'

def brainfuck2list(brainfuck):
  while brainfuck:               #if list is empty then finish
    e = brainfuck.pop(0)
    if e not in ("[","]"):
      yield e
    elif e == "[":
      yield list(brainfuck2list(brainfuck))
    else:
      break

[_ for _ in brainfuck2list(list(s))]

你得到以下输出

[
  ',', '>', ',', '<', 
  [
    '>', 
    [
      '-', '>', '+', '>', '+', '<', '<'
    ]
    , '>', '>', 
    [
      '-','<', '<', '+', '>', '>'
    ], 
    '<', '<', '<', '-'
  ]
  , '>', '>', '.'
]

出于好奇,这是我使用递归的工作解决方案:

def tokenize(code):
  instructions = deque()

  if len(code) > 0:
    while len(code) > 0:
      if code[0] is "[":
        code.popleft()

        group = deque()
        r = 0

        while r > -1 and len(code) > 0:
          if code[0] is '[':
            group.append(code.popleft())
            r += 1

          elif code[0] is ']':
            if r is 0: 
              code.popleft()

            else:
              group.append(code.popleft())

            r -= 1

          else:
            group.append(code.popleft())

        instructions.append(tokenize(group))

      else:
        instructions.append(code.popleft())

    return instructions

else:
  return instructions