【问题标题】:Manipulate string containing parenthesis in Python在 Python 中操作包含括号的字符串
【发布时间】:2021-01-09 08:21:44
【问题描述】:

假设我有一个这样的字符串,

"(a=1) and ((b=2) or (c=3))"

哪里有 "and" 我需要在 python 中将其转换为 this,

"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") & (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") & (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") & (User_Values.value.contains([{"value":"exampleorg"}]))))'

进展:-

正在尝试使用“pyparsing”库来获取操作数的外括号内容。

ms = '((Attributes.name=="usertype") & (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") & (User_Values.value.contains([{"type":"examplecom"}]))) and ((Attributes.name=="emails") & (User_Values.value.contains([{"value":"exampleorg"}]))))'

scanner = originalTextFor(nestedExpr('(',')'))

for match in scanner.searchString(ms):
    print("match is ..........", match[0])

知道了,

((Attributes.name=="usertype") & (cast(User_Values.value, db.String())==Employee))
(((Attributes.name=="emails") & (User_Values.value.contains([{"type":"examplecom"}]))) and ((Attributes.name=="emails") & (User_Values.value.contains([{"value":"exampleorg"}]))))

接下来我要获取操作数的最外层括号内容。 在上面的例子中没有发生这种情况。它只是给出了两个独立的括号内容。

2020 年 10 月 8 日编辑

Ken T 的解决方案是有道理的,但我注意到那里有一个问题。

"((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") & (cast(Values.value, db.String()).like('"%a%"'))) and ((Values.attribute=="3") & (cast(Values.value, db.String()).like('"%b%"')))) and ((Values.attribute=="1") & (cast(Values.value, db.String()).like('"%a%"')))'

预期的输出是,

query[((Values.attribute=="1") & (cast(Values.value, db.String()).like(%a%)))]
.add(query[(Values.attribute=="3") & (cast(Values.value, db.String()).like(%b%))])
.add(query[(Values.attribute=="1") & (cast(Values.value, db.String()).like(%a%)]))

但实际输出是,

query[(((Values.attribute=="1") & (cast(Values.value, db.String()).like(%a%)))]
.add(query[(Values.attribute=="3") & (cast(Values.value, db.String()).like(%b%))))]
.add(query[(Values.attribute=="1") & (cast(Values.value, db.String()).like(%a%)]))

注意括号。

query[]

中不能有and .add()

如何纠正 Ken T 的解决方案。

【问题讨论】:

  • 使用python默认re你不能匹配嵌套的括号。
  • 还有哪些可用的选项
  • 使用regex 模块实现 PCRE 功能。
  • 您的第二个示例不一致,每个 and 有 2 个操作数 - 所以对于 2 个 ands 它应该是 4 个查询,而不是 3 个。您没有在第一个 add 之后包装所有语句与query。根据您的解释,查看嵌套and 的其他方式应该导致嵌套query。我说的对吗?
  • 我检查了我的用例,只为单个操作数添加查询

标签: python regex string recursion pyparsing


【解决方案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") & (cast(User_Values.value, db.String())=='"Employee"')) and (((Attributes.name=="emails") & (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") & (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") & (cast(User_Values.value, db.String())=='"Employee"'))].add(query[((Attributes.name=="emails") & (User_Values.value.contains([{"type":"examplecom"}]))) or ((Attributes.name=="emails") & (User_Values.value.contains([{"value":"exampleorg"}])))])

您可以在以下网站以交互方式测试正则表达式模式:

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

【讨论】:

  • 我注意到这个解决方案存在一个问题。请查看我的最新编辑。
  • 对于输入,"(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)])
  • 而且query[]里面不能有and()
  • @Mohan 这就是为什么在问题中选择好的例子如此重要的原因。此解决方案适用于最初发布的所有示例,但由于正则表达式的限制,我怀疑它是否可以轻松修改以满足新要求。
  • 有很多可能的例子,不幸的是我最近注意到了这一点
猜你喜欢
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-30
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2022-07-06
  • 2019-11-25
相关资源
最近更新 更多