我想推出一个能够匹配存储在 exp
中的数学表达式的正则表达式。
表达式的模式以括号开头和结尾,不能包含任何字母。表达式可以包含整数或浮点数,运算符可以是 +-*/**
。表达式长度不限。
这是我的正则表达式:
import re
re.match(r'^[(]([(-]?([0-9]+)[)]??)([(]?([-+/*]([0-9]))?([.]?[0-9]+)?[)])[)]*$', exp)
但是我的正则表达式与某些字符串不匹配。 例如:
exp = '(( 200 + (4 * 3.14)) / ( 2 ** 3 ))'
exp = '(23.23+23)'
exp = '((23**2)/23)'
exp = '(23.34-(3*2))'
我是正则表达式新手,不知道是哪部分表达式有问题,麻烦大家见谅,希望有人能帮我解决。 非常感谢!
答案 0 :(得分:1)
您可以将其视为“拆分”字符串,并将运算符作为分隔符。这将使您免于尝试在正则表达式中表示数字。
所以你只需要一个表达式来选取 5 个运算符和括号。这可以使用运算符之间的管道来表示,最长的运算符 (**) 排在第一位。
import re
symbols = ["**","+","-","*","/","(",")"] # longest first
tokens = re.compile("("+"|".join(map(re.escape,symbols))+")")
# placing symbols in a group makes re.split keep the separators
def tokenize(exp):
parts = map(str.strip,tokens.split(exp)) # split and strip spaces
return list(filter(None,parts)) # remove empty parts
exp = '(( 200 + (4 * 3.14)) / ( 2 ** 3 ))'
print(tokenize(exp))
['(', '(', '200', '+', '(', '4', '*', '3.14', ')', ')', '/', '(', '2', '**', '3', ')', ')']
exp = '(23.23+23)'
print(tokenize(exp))
['(', '23.23', '+', '23', ')']
exp = '((23**2)/23)'
print(tokenize(exp))
['(', '(', '23', '**', '2', ')', '/', '23', ')']
exp = '(23.34-(3*2))'
print(tokenize(exp))
['(', '23.34', '-', '(', '3', '*', '2', ')', ')']
然后您可以执行第二遍并验证组件是运算符还是有效数字,并检查表达式是否格式正确,带有匹配的括号和交替的运算符/操作数。到那时,您将确切地知道表达式的哪一部分是不正确的。
例如:
def validate(exp):
parts = tokenize(exp)
error = ""
pLevel = 0
previous = "$"
for errorPos,part in enumerate(parts):
pLevel += (part=="(")-(part==")")
if pLevel<0: error="too many closing parentheses";break
if part in "**+/)" and previous in "$**+-/(" :
error = "missing operand";break
if part not in "**+-/)" and previous not in "$**+-/(":
error = "missing operator";break
previous = part
if part in ["**","*","+","-","/","(",")"]: continue
if all(p.isdigit() for p in part.split(".",1)): continue
error = "invalid operand: " + part
break
if not error and pLevel!=0:
errorPos,error = len(parts),"unbalanced parentheses"
if not error and previous in "**+-/":
errorPos,error = len(parts),"missing operand"
if error:
print("".join(parts))
indent = " " * sum(map(len,parts[:errorPos]))
print(indent+"^")
print(indent+"|__ Error!",error)
...
validate('(( 200 + (4 * 3,14)) / ( 2 ** 3 ))')
((200+(4*3,14))/(2**3))
^
|__ Error! invalid operand: 3,14
validate('(( 200 + (4 * 3.14)) / ( 2 ** 3 )')
((200+(4*3.14))/(2**3)
^
|__ Error! unbalanced parentheses
validate('(( 200 + (4 * 3.14)))) / ( 2 ** 3 )')
((200+(4*3.14))))/(2**3)
^
|__ Error! too many closing parentheses
validate('(( 200 + *(4 * 3,14)) / ( 2 ** 3 ))')
((200+*(4*3,14))/(2**3))
^
|__ Error! missing operand
validate('(( 200 + ()(4 * 3,14)) / ( 2 ** 3 ))')
((200+()(4*3,14))/(2**3))
^
|__ Error! missing operand
validate('(( (200 + )(4 * 3,14)) / ( 2 ** 3 ))')
(((200+)(4*3,14))/(2**3))
^
|__ Error! missing operand
validate('(( (200 + 2)(4 * 3,14)) / ( 2 ** 3 ))')
(((200+2)(4*3,14))/(2**3))
^
|__ Error! missing operator