Thanks for the link to pyparsing. This is actually a pretty involved expression to process using regexen. Not only are there groups in parentheses with comparison operators, but logical operators as well.
Here is an initial pyparsing parser, using its infix_notation helper function. infix_notation takes an expression for the base operand (in this case an identifier or a real or integer number) and a list of tuples that specify the operators, their arity, and left- or right-associativity. The order of the tuples in the list indicates their precedence of operations.
import pyparsing as pp
# define expressions that will be parsed as expression operands
ident = pp.Word(pp.alphas, pp.alphanums)
integer = pp.Word(pp.nums)
real = pp.Regex("\d+\.\d+")
comparison_op = pp.one_of("> < >= <= != ==")
expr = pp.infix_notation(
ident | real | integer,
[
(comparison_op, 2, pp.OpAssoc.LEFT),
("&&", 2, pp.OpAssoc.LEFT),
("||", 2, pp.OpAssoc.LEFT),
]
)
Pyparsing expressions have a run_tests method that makes it easy to process a number of sample strings:
expr.run_tests("""\
(FS22 > 15) && (FS22 < 46) || (FS33 > 0.0)
(FS33 > 0.0) || (FS34> 15) && (FS22 < 46) || (FS33 > 0.0)
(FS33 > 0.0) || (FS34> 15) && (FS22 < 46) || (FS33 > 0.0) && (FS39> 15)
""")
The output can be fairly verbose, especially with deeply nested data, but an abbreviated form is:
(FS22 > 15) && (FS22 < 46) || (FS33 > 0.0)
[[[['FS22', '>', '15'], '&&', ['FS22', '<', '46']], '||', ['FS33', '>', '0.0']]]
(FS33 > 0.0) || (FS34> 15) && (FS22 < 46) || (FS33 > 0.0)
[[['FS33', '>', '0.0'], '||', [['FS34', '>', '15'], '&&', ['FS22', '<', '46']], '||', ['FS33', '>', '0.0']]]
(FS33 > 0.0) || (FS34> 15) && (FS22 < 46) || (FS33 > 0.0) && (FS39> 15)
[[['FS33', '>', '0.0'], '||', [['FS34', '>', '15'], '&&', ['FS22', '<', '46']], '||', [['FS33', '>', '0.0'], '&&', ['FS39', '>', '15']]]]
If you look closely, you’ll see that the “&&” operations are grouped, indicating their higher precedence. Also the parenthesized parts are grouped as well, and if parentheses were added to override the operator precedence, those would also be grouped.
Actually evalutating this expression can be done, but is a much longer story than covered in this post. The pyparsing repo includes several examples using infix_notation, eval_arith.py is probably closest to this parser, and simpleBool.py includes evaluation of logical operations.