使用 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
跟随 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