#python #regex #string #recursion #pyparsing
#python #регулярное выражение #строка #рекурсия #pyparsing
Вопрос:
Допустим, у меня есть строка, подобная этой,
"(a=1) and ((b=2) or (c=3))"
Где бы ни было «и», мне нужно преобразовать его в this в python,
"query[(a=1)].add(query[(b=2) or (c=3)])"
как вы можете видеть, происходят две вещи:
когда я когда-либо делаю add, я оборачиваю операнды с помощью query[] и преобразую a and b
в a.add(b)
.
Еще один пример, если строка имеет вид,
"(a=1) and ((b=2) and (c=3))"
где есть два и
результат должен быть,
"query[(a=1)].add(query[(b=2)].add(query[(c=3)]))"
Я не могу это жестко запрограммировать, потому что круглые скобки могут быть любого вложенного уровня.
Выражение, которое я показал выше, является упрощенным для объяснения, оно также может быть таким,
'((Attributes.name=="usertype") amp; (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") amp; (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") amp; (User_Values.value.contains([{"value":"exampleorg"}]))))'
Прогресс:-
Пытался использовать библиотеку «pyparsing», чтобы получить содержимое внешних скобок операндов.
ms = '((Attributes.name=="usertype") amp; (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") amp; (User_Values.value.contains([{"type":"examplecom"}]))) and ((Attributes.name=="emails") amp; (User_Values.value.contains([{"value":"exampleorg"}]))))'
scanner = originalTextFor(nestedExpr('(',')'))
for match in scanner.searchString(ms):
print("match is ..........", match[0])
получил это,
((Attributes.name=="usertype") amp; (cast(User_Values.value, db.String())==Employee))
(((Attributes.name=="emails") amp; (User_Values.value.contains([{"type":"examplecom"}]))) and ((Attributes.name=="emails") amp; (User_Values.value.contains([{"value":"exampleorg"}]))))
далее я ищу, чтобы получить содержимое самых внешних круглых скобок операндов и .
В приведенном выше примере этого не происходит. Это просто дает два независимых содержимого круглых скобок.
Редактировать 8 октября 2020 года
Решение Кена Т имеет смысл, но я замечаю там проблему.
"((b=2) and (c=3)) and (a=1)"
где есть два и
результат должен быть,
"query[(b=2)].add(query[(c=3)]).add(query[(a=1)])"
но результат,
query[((b=2)].add(query[c=3)) and (a=1])
Пример,
для ввода,
'(((Values.attribute=="1") amp; (cast(Values.value, db.String()).like('"%a%"'))) and ((Values.attribute=="3") amp; (cast(Values.value, db.String()).like('"%b%"')))) and ((Values.attribute=="1") amp; (cast(Values.value, db.String()).like('"%a%"')))'
Ожидаемый результат,
query[((Values.attribute=="1") amp; (cast(Values.value, db.String()).like(%a%)))]
.add(query[(Values.attribute=="3") amp; (cast(Values.value, db.String()).like(%b%))])
.add(query[(Values.attribute=="1") amp; (cast(Values.value, db.String()).like(%a%)]))
но фактический результат,
query[(((Values.attribute=="1") amp; (cast(Values.value, db.String()).like(%a%)))]
.add(query[(Values.attribute=="3") amp; (cast(Values.value, db.String()).like(%b%))))]
.add(query[(Values.attribute=="1") amp; (cast(Values.value, db.String()).like(%a%)]))
обратите внимание на круглые скобки.
внутри запроса не должно быть and .add()[]
Как мне исправить решение Кена Т.
Комментарии:
1. Используя python по умолчанию
re
, вы не можете сопоставить вложенные круглые скобки.2. какие другие доступные варианты
3. Используйте
regex
модуль для возможности PCRE.4. Ваш второй пример непоследователен, каждый
and
из них имеет 2 операнда — поэтому за 2and
секунды должно быть 4 запроса, а не 3. Вы не обернули все операторы после первогоadd
сquery
помощью . Другой способ взглянуть на то, что вложенноеand
должно приводить к вложенномуquery
в соответствии с вашим объяснением. Я прав?5. Я проверил свой вариант использования, запрос добавляется только для одиночных операндов
Ответ №1:
Рекурсивно! Это рекурсивная проблема.
import re
def queryGen(text, lastOP=''):
pattern = re.compile("((. ?))s (and|or) s((. ))")
res = pattern.search(text)
if not res:
if lastOP == 'or':
return text
elif lastOP == 'and':
return f'query[{text}]'
if res.group(2)=='and':
return f"query[({res.group(1)})].add({queryGen(res.group(3), lastOP='and')})"
if res.group(2)=='or':
return f"query[({res.group(1)}) or ({queryGen(res.group(3), lastOP='or')})]"
print(queryGen("(a=1) and ((b=2) or (c=3))"))
print(queryGen("(a=1) and ((b=2) and (c=3))"))
print(queryGen("""((Attributes.name=="usertype") amp; (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") amp; (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") amp; (User_Values.value.contains([{"value":"exampleorg"}]))))"""))
Возврат:
query[(a=1)].add(query[(b=2) or (c=3)])
query[(a=1)].add(query[(b=2)].add(query[c=3]))
query[((Attributes.name=="usertype") amp; (cast(User_Values.value, db.String())=='"Employee"'))].add(query[((Attributes.name=="emails") amp; (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") amp; (User_Values.value.contains([{"value":"exampleorg"}])))])
Вы можете интерактивно протестировать шаблон регулярного выражения на следующем веб-сайте:
Комментарии:
1. Я заметил одну проблему с этим решением. Пожалуйста, посмотрите на мое последнее редактирование.
2. для ввода,
"(a=1) and ((b=2) and (c=3))"
, решение правильное, но если мы изменим его, как"((b=2) and (c=3)) and (a=1)"
решение неверно. Это даетquery[((b=2)].add(query[c=3)) and (a=1])
. что неверно. и ожидаемое решение,query[(b=2)].add(query[(c=3)]).add(query[(a=1)])
3. и внутри запроса [] не может быть and()
4. @Mohan вот почему так важно выбрать хорошие примеры в вопросе. Это решение работало для всех первоначально опубликованных примеров, но я сомневаюсь, что его можно легко изменить в соответствии с новыми требованиями из-за ограничений регулярного выражения.
5. существует много возможных примеров, к сожалению, я заметил это недавно