Hallo zusammen,
kann mir jemand hier irgendwie helfen:
ich werte Daten aus und bekomme zb. als Ergebnis einen String
code = ' ((1 or 0 or 0 and 1) or (0 or 0 and 1) and not 0)'
nun will als Ergebnis newcode = ((1 or 0 or 0 and 1) or (0 or 0 and 1) and not 0)
und am Ende True or False
ich wäre sehr dankbar wenn jemand eine Idee für mich hat
statt " 1 and 0 or 1 " => 1 and 0 or 1
- __blackjack__
- User
- Beiträge: 13077
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Spasseshalber mal mit `redbaron` gelöst, weil sich dessen Parser (fälschlicherweise) nicht an dem führenden Leerzeichen in `code` stört, im Gegensatz zum `ast.parser`, mit dem das natürlich ansonsten grundsätzlich analog funktionieren würde:
Code: Alles auswählen
#!/usr/bin/env python3
from functools import singledispatch
from operator import and_, or_
from redbaron import RedBaron
from redbaron.nodes import (
AssociativeParenthesisNode,
BooleanOperatorNode,
IntNode,
UnitaryOperatorNode,
)
NAME_TO_FUNCTION = {'and': and_, 'or': or_}
@singledispatch
def evaluate(node):
raise ValueError(f'Unknown node type {type(node)}: {node.dumps()}')
@evaluate.register(AssociativeParenthesisNode)
def evaluate_parenthesis(node):
return evaluate(node.value)
@evaluate.register(UnitaryOperatorNode)
def evaluate_unitary_operator(node):
if node.value != 'not':
raise ValueError(f'Unknown unitary operator {node.value!r}')
else:
return not evaluate(node.target)
@evaluate.register(BooleanOperatorNode)
def evaluate_boolean_operator(node):
operator = NAME_TO_FUNCTION[node.value]
return operator(evaluate(node.first), evaluate(node.second))
@evaluate.register(IntNode)
def evaluate_int(node):
value = int(node.value)
if value not in [0, 1]:
raise ValueError(f'Unexcpected value {value} not 0 or 1')
return bool(value)
def main():
code = ' ((1 or 0 or 0 and 1) or (0 or 0 and 1) and not 0)'
red = RedBaron(code)
if not red:
raise ValueError('No code found.')
print(evaluate(red[0]))
if __name__ == "__main__":
main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
- __blackjack__
- User
- Beiträge: 13077
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Wie schon geschrieben, mit `ast.parse()` geht das analog:
Code: Alles auswählen
#!/usr/bin/env python3
import ast
from ast import And, BoolOp, Expr, Not, Num, Or, UnaryOp
from functools import reduce, singledispatch
from operator import and_, or_
TYPE_TO_OPERATOR_FUNCTION = {And: and_, Or: or_}
@singledispatch
def evaluate(node):
raise ValueError(f'Unknown node type {type(node)}: {ast.dump(node)}')
@evaluate.register(Expr)
def evaluate_expression(node):
return evaluate(node.value)
@evaluate.register(UnaryOp)
def evaluate_not(node):
if not isinstance(node.op, Not):
raise ValueError(f'Unknown unitary operator {node.op}')
else:
return not evaluate(node.operand)
@evaluate.register(BoolOp)
def evaluate_boolean_operation(node):
operator = TYPE_TO_OPERATOR_FUNCTION[type(node.op)]
return reduce(operator, map(evaluate, node.values))
@evaluate.register(Num)
def evaluate_number(node):
if node.n not in [0, 1]:
raise ValueError(f'Unexcpected value {node.n} not 0 or 1')
else:
return bool(node.n)
def main():
code = '((1 or 0 or 0 and 1) or (0 or 0 and 1) and not 0)'
print(evaluate(ast.parse(code, mode='single').body[0]))
if __name__ == "__main__":
main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
- __blackjack__
- User
- Beiträge: 13077
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Wenn man sich keinen fertigen Python-Parser hernehmen möchte, kann man sich natürlich auch selbst einen Parser schreiben. Zum Beispiel mit Pyparsing:
Code: Alles auswählen
#!/usr/bin/env python3
from functools import reduce
from operator import and_, or_
import pyparsing as pp
VALUE = pp.oneOf('0 1').setParseAction(lambda s, loc, toks: bool(int(toks[0])))
NOT, AND, OR = (pp.Suppress(s).setName(s) for s in ['not', 'and', 'or'])
EXPRESSION = pp.infixNotation(
VALUE,
[
(NOT, 1, pp.opAssoc.RIGHT, lambda s, loc, toks: not toks[0][0]),
(AND, 2, pp.opAssoc.LEFT, lambda s, loc, toks: reduce(and_, toks[0])),
(OR, 2, pp.opAssoc.LEFT, lambda s, loc, toks: reduce(or_, toks[0])),
]
)
GRAMMAR = EXPRESSION + pp.lineEnd
GRAMMAR.enablePackrat()
def main():
source = '((1 or 0 or 0 and 1) or (0 or 0 and 1) and not 0)'
try:
result = GRAMMAR.parseString(source)
except pp.ParseException as error:
print(error)
else:
print(result[0])
if __name__ == "__main__":
main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman