Во-первых, вот мой текущий код (который должен работать, если вы просто скопируете его, по крайней мере, для моего Python 3.11.9 и pyparsing 3.1.2):
Код: Выделить всё
import pyparsing as pp
# Define the components of the grammar
field_name = pp.Word(pp.alphas + "_", pp.alphanums + "_")
action = pp.one_of("include exclude")
sub_action = pp.one_of("equals contains starts_with ends_with greater_than not_equals not_contains not_starts_with not_ends_with empty not_empty less_than less_than_or_equal_to greater_than_or_equal_to between regex in_list not_in_list")
# Custom regex pattern parser that handles regex ending at the first space
def regex_pattern():
def parse_regex(t):
# Join tokens to form the regex pattern
return ''.join(t[0])
return pp.Regex(r'[^ ]+')("regex").setParseAction(parse_regex)
# Define value as either a quoted string, a regex pattern, or a simple word with allowed characters
quoted_string = pp.QuotedString('"')
unquoted_value = pp.Word(pp.alphanums + "_-;, ") | pp.Regex(r'[^/]+')
value = pp.Optional(quoted_string | regex_pattern() | unquoted_value)("value")
slash = pp.Suppress("/")
filter_expr = pp.Group(field_name("field") + slash + action("action") + slash + sub_action("sub_action") + pp.Optional(slash + value, default=""))
# Define logical operators
and_op = pp.one_of("AND and")
or_op = pp.one_of("OR or")
not_op = pp.one_of("NOT not")
# Define the overall expression using infix notation
expression = pp.infixNotation(filter_expr,
[
(not_op, 1, pp.opAssoc.RIGHT),
(and_op, 2, pp.opAssoc.LEFT),
(or_op, 2, pp.opAssoc.LEFT)
])
# List of test filters
test_filters = [
"order_type/exclude/contains/STOP ORDER AND order_validity/exclude/contains/GOOD FOR DAY",
"order_status/include/regex/^New$ AND order_id/include/equals/123;124;125",
"order_id/include/equals/123;124;125",
"order_id/include/equals/125 OR currency/include/equals/EUR",
"trade_amount/include/greater_than/1500 AND currency/include/equals/USD",
"trade_amount/include/between/1200-2000 AND currency/include/in_list/USD,EUR",
"order_status/include/starts_with/New;Filled OR order_status/include/ends_with/ed",
"order_status/exclude/empty AND filter_code/include/not_empty",
"order_status/include/regex/^New$",
"order_status/include/regex/^New$ OR order_status/include/regex/^Changed$",
"order_status/include/contains/New;Changed"
]
# Loop over test filters, parse each, and display the results
for test_string in test_filters:
print(f"Testing filter: {test_string}")
try:
parse_result = expression.parse_string(test_string, parseAll=True).asList()[0]
print(f"Parsed result: {parse_result}")
except Exception as e:
print(f"Error with filter: {test_string}")
print(e)
print("\n")
Проблема (насколько я могу судить) заключается в том, что пустое пространство между "STOP" и "ORDER" распознается как конец части «значения» этой части группы, а затем ломается.
Я пробовал использовать Skipsto, чтобы просто перейти к следующему логическому оператор после завершения части sub_action, но это не сработало. Кроме того, я не был уверен, насколько это расширяемо, потому что теоретически должно быть возможно даже иметь множество связанных выражений (например, часть1 И часть2 ИЛИ часть3), где каждая часть состоит из 3-4 элементов (имя_поля, действие, под_действие). и необязательное значение).
Я также пытался расширить unquoted_value, включив в него пустые места, но это тоже ничего не изменило.
Я Я также просмотрел некоторые примеры на https://github.com/pyparsing/pyparsing/ ... r/examples, но я не смог увидеть ничего похожего на мой вариант использования. (Возможно, когда мой код заработает правильно, его можно будет добавить сюда в качестве примера, не уверен, насколько мой случай будет полезен другим).
Подробнее здесь: https://stackoverflow.com/questions/790 ... xpressions