Fer*_*aku 14 python string split tokenize python-3.x
我做了一个程序,在python中将中缀转换为postfix.问题是当我介绍这些论点时.如果我介绍这样的东西:(这将是一个字符串)
( ( 73 + ( ( 34 - 72 ) / ( 33 - 3 ) ) ) + ( 56 + ( 95 - 28 ) ) )
Run Code Online (Sandbox Code Playgroud)
它将使用.split()拆分它,程序将正常工作.但我希望用户能够介绍这样的东西:
((73 + ( (34- 72 ) / ( 33 -3) )) + (56 +(95 - 28) ) )
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,我希望空格可以是微不足道的,但是程序继续用括号,整数(不是数字)和操作数来分割字符串.
我尝试解决它for
但我不知道如何捕获整数(73,34,72)而不是一位数(7,3,3,4,7,2)
总而言之,我想要的是将一个字符串((81 * 6) /42+ (3-1))
分成:
[(, (, 81, *, 6, ), /, 42, +, (, 3, -, 1, ), )]
Run Code Online (Sandbox Code Playgroud)
Eri*_*nil 21
ast
您可以使用ast
获取表达式的树:
import ast
source = '((81 * 6) /42+ (3-1))'
node = ast.parse(source)
def show_children(node, level=0):
if isinstance(node, ast.Num):
print(' ' * level + str(node.n))
else:
print(' ' * level + str(node))
for child in ast.iter_child_nodes(node):
show_children(child, level+1)
show_children(node)
Run Code Online (Sandbox Code Playgroud)
它输出:
<_ast.Module object at 0x7f56abbc5490>
<_ast.Expr object at 0x7f56abbc5350>
<_ast.BinOp object at 0x7f56abbc5450>
<_ast.BinOp object at 0x7f56abbc5390>
<_ast.BinOp object at 0x7f56abb57cd0>
81
<_ast.Mult object at 0x7f56abbd0dd0>
6
<_ast.Div object at 0x7f56abbd0e50>
42
<_ast.Add object at 0x7f56abbd0cd0>
<_ast.BinOp object at 0x7f56abb57dd0>
3
<_ast.Sub object at 0x7f56abbd0d50>
1
Run Code Online (Sandbox Code Playgroud)
正如@ user2357112在评论中写道:ast.parse
解释Python语法,而不是数学表达式.(1+2)(3+4)
将被解析为函数调用,并且列表推导将被接受,即使它们可能不应被视为有效的数学表达式.
如果你想要一个扁平结构,正则表达式可以工作:
import re
number_or_symbol = re.compile('(\d+|[^ 0-9])')
print(re.findall(number_or_symbol, source))
# ['(', '(', '81', '*', '6', ')', '/', '42', '+', '(', '3', '-', '1', ')', ')']
Run Code Online (Sandbox Code Playgroud)
它寻找:
获得元素列表后,您可以检查语法是否正确,例如使用a stack
检查括号是否匹配,或者每个元素是否为已知元素.
Hor*_*man 12
您需要为输入实现一个非常简单的标记生成器.您有以下类型的令牌:
您可以在输入字符串中找到它们,这些字符串由各种空格分隔.
所以第一步是从开始到结束处理字符串,然后提取这些标记,然后在标记上进行解析,而不是在字符串本身上进行解析.
一个很好的方法是使用以下正则表达式:'\s*([()+*/-]|\d+)'
.然后你可以:
import re
the_input='(3+(2*5))'
tokens = []
tokenizer = re.compile(r'\s*([()+*/-]|\d+)')
current_pos = 0
while current_pos < len(the_input):
match = tokenizer.match(the_input, current_pos)
if match is None:
raise Error('Syntax error')
tokens.append(match.group(1))
current_pos = match.end()
print(tokens)
Run Code Online (Sandbox Code Playgroud)
这将打印 ['(', '3', '+', '(', '2', '*', '5', ')', ')']
你也可以使用re.findall
或re.finditer
,但是你会跳过不匹配,在这种情况下是语法错误.
如果你不想使用re
模块,你可以试试这个:
s="((81 * 6) /42+ (3-1))"
r=[""]
for i in s.replace(" ",""):
if i.isdigit() and r[-1].isdigit():
r[-1]=r[-1]+i
else:
r.append(i)
print(r[1:])
Run Code Online (Sandbox Code Playgroud)
输出:
['(', '(', '81', '*', '6', ')', '/', '42', '+', '(', '3', '-', '1', ')', ')']
Run Code Online (Sandbox Code Playgroud)
手动滚动一个简单的表达式标记化器实际上是非常简单的.而且我认为你也会以这种方式学到更多东西.
因此,为了教育和学习,这是一个可以扩展的简单表达式标记器实现.它基于"最大 - 多"规则工作.这意味着它行为"贪婪",试图消耗尽可能多的字符来构造每个令牌.
不用多说,这里是tokenizer:
class ExpressionTokenizer:
def __init__(self, expression, operators):
self.buffer = expression
self.pos = 0
self.operators = operators
def _next_token(self):
atom = self._get_atom()
while atom and atom.isspace():
self._skip_whitespace()
atom = self._get_atom()
if atom is None:
return None
elif atom.isdigit():
return self._tokenize_number()
elif atom in self.operators:
return self._tokenize_operator()
else:
raise SyntaxError()
def _skip_whitespace(self):
while self._get_atom():
if self._get_atom().isspace():
self.pos += 1
else:
break
def _tokenize_number(self):
endpos = self.pos + 1
while self._get_atom(endpos) and self._get_atom(endpos).isdigit():
endpos += 1
number = self.buffer[self.pos:endpos]
self.pos = endpos
return number
def _tokenize_operator(self):
operator = self.buffer[self.pos]
self.pos += 1
return operator
def _get_atom(self, pos=None):
pos = pos or self.pos
try:
return self.buffer[pos]
except IndexError:
return None
def tokenize(self):
while True:
token = self._next_token()
if token is None:
break
else:
yield token
Run Code Online (Sandbox Code Playgroud)
这是一个演示用法:
tokenizer = ExpressionTokenizer('((81 * 6) /42+ (3-1))', {'+', '-', '*', '/', '(', ')'})
for token in tokenizer.tokenize():
print(token)
Run Code Online (Sandbox Code Playgroud)
产生输出:
(
(
81
*
6
)
/
42
+
(
3
-
1
)
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4282 次 |
最近记录: |