【问题标题】:Python Regex: Select everything between two brackets ignore brackets in betweenPython正则表达式:选择两个括号之间的所有内容忽略中间的括号
【发布时间】:2021-12-06 12:45:17
【问题描述】:

我想捕获整个子查询,无论中间是否有连接或子字符串函数(即忽略子查询中的另一个括号打开和关闭。(a)我们不想将“加入”捕获为一个单词 (b) “alias2” 不会总是跟在“join”之后,它可以是任何东西(单词边界、空格或“join”单词)。

案例 1:select 中没有 concat 或 sub-string 函数

  • 在: (select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2 join

  • 输出: (select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2

案例 2:select 中的 Concat 函数

  • 在: (select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2 join

  • 输出: (select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2

我尝试过的:

方法一:re.findall('\(select.*?\)\s[a-zA-Z0-9_]+', input statement)

方法 2:如 @TheFourthBird 建议的那样

import re
pat1 = '\(select.*?\)\s[a-zA-Z0-9_]+'
pat2 = "\(select [^()]*(?:(\((?>[^()]+|(?1))*\)))?[^()]*\)[^()\n]+"

string1 = "(select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2"
string2 = "(select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2"

print(re.findall(pat1, string1))
print(re.findall(pat1, string2))

import regex as re
print(re.findall(pat2, string1))
print(re.findall(pat2, string2))

pattern = re.compile(pat2, re.UNICODE)
print([match.group(0) for match in pattern.finditer(string2)])

输出:

["(select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2"]
['(select concat(t1.col1, t2.col1, t3.col1) as']
['']
['(t1.col1, t2.col1, t3.col1)']
["(select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2 join "]

上述方法有什么问题:

  • 方法 1:适用于案例 1,但不适用于案例 2。

  • 方法 2:仍然行不通!但是,["(select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2 join "] 是最符合预期的。但是,它不应该捕获 alias2 旁边的内容。

请帮帮我!

【问题讨论】:

  • 你安装了还是安装了pypi.org/project/regex
  • 你有我建议的模式的旧版本,应该是like this\(select [^()]*(?:(\((?>[^()]+|(?1))*\)))?[^()]*\)\s[a-zA-Z0-9_]+
  • 这与旧版本无关。模式变了!!让我看看它现在是否有效。
  • 现在使用您现在建议的模式适用于上述示例。谢谢@Thefourthbird。

标签: mysql python-3.x regex


【解决方案1】:

您可以先匹配(select ,然后可以选择使用PyPi regex module 匹配平衡括号。

在模式的末尾,匹配一个空白字符并使用您的字符类。

\(select [^()]*(?:(\((?>[^()]+|(?1))*\)))?[^()]*\)\s[a-zA-Z0-9_]+

部分模式匹配:

  • \(select 匹配(select
  • [^()]* 可选匹配除 () 之外的任何字符
  • (?:非捕获组
    • ( 捕获第 1 组
      • \((?>[^()]+|(?1))*\) 匹配 ( 并使用递归模式递归第一个子组(捕获组 1),最后匹配 )
    • )关闭第一组
  • )?关闭非捕获组并使其可选
  • [^()]*\) 可选匹配除括号外的任何字符,然后匹配 )
  • \s[a-zA-Z0-9_]+ 匹配一个空白字符和字符类中列出的 1+

查看regex demoPython demo

例如,使用 re.finditer (因为 re.findall 返回捕获组值)

import regex as re

pattern = r"\(select [^()]*(?:(\((?>[^()]+|(?1))*\)))?[^()]*\)\s[a-zA-Z0-9_]+"

s = ("In: (select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2\n\n"
    "Out: (select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2\n\n"
    "In: (select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2\n\n"
    "Out: (select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2\n")

matches = re.finditer(pattern, s)

for matchNum, match in enumerate(matches, start=1):
    
    print(match.group())

输出

["(select t1.col1 as alias1 from db.tb where t1.col1='val1') alias2"]
["(select concat(t1.col1, t2.col1, t3.col1) as alias1 from db.tb where t1.col1='val1') alias2"]

注意匹配 SQL 容易出错。

【讨论】:

    猜你喜欢
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多