Манипулировать строкой, содержащей круглые скобки в Python

#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 операнда — поэтому за 2 and секунды должно быть 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"}])))])
  

Вы можете интерактивно протестировать шаблон регулярного выражения на следующем веб-сайте:

https://regex101.com/r/C1GFuS/1

Комментарии:

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. существует много возможных примеров, к сожалению, я заметил это недавно