使用正则表达式保留中间字符串
Posted
技术标签:
【中文标题】使用正则表达式保留中间字符串【英文标题】:Retain intermediate string using regex 【发布时间】:2021-11-27 00:01:11 【问题描述】:我想在多个 python 代码文件中的所有出现处将子字符串附加到字符串模式。然而,原始字符串遵循一个模式,并且每次都不是完全相同的字符串。 以下是一些变体示例:
Original Code: a.b();
Want Code: a.b().c();
Original Code: a.b(param1=1);
Want Code: a.b(param1=1, param2=2).c();
Original Code: a.b(param1=1, param2=2);
Want Code: a.b(param1=1, param2=2).c();
Original Code: a.b(param1=D());
Want Code: a.b(param1==D()).c();
Original Code: X(a.b(param1=D()));
Want Code: X(a.b(param1==D()).c());
更新: 由于我试图替换文件中的代码,因此该文件包含缩进和新行以提高可读性: 例如
Original Code: X(a.b(
param1=D()
)
);
Want Code: X(a.b(
param1=D()
).c()
);
Original Code: X(a.b(
param1=D(),
param2="qwerty"
)
);
Want Code: X(a.b(
param1=D(),
param2="qwerty"
).c()
);
Original Code: X(a.b(
newObj())
);
Want Code: X(a.b(
newObj()).c()
);
我并不真正关心函数 b 中传递的参数。我只需要在每次调用 a.b() 时附加对 c() 的调用。
我正在使用正则表达式'a.b(.*?)'
来检测适当的原始代码。我尝试使用
以下解决方案正则表达式:a.b($1).c()
或 a.b(\1).c()
但无济于事。
【问题讨论】:
【参考方案1】:你可以使用
a\.b\([^()]*\)(?=;)
a\.b
从字面上匹配并转义点
\([^()]*\)
使用否定字符类从左括号匹配到右括号
(?=;)
正向前瞻,在右侧断言 ;
Regex demo | Python demo
并替换为完整匹配 \g<0>
后跟 .c()
\g<0>.c()
例如:
import re
regex = r"a\.b\([^()]*\)(?=;)"
s = ("a.b();\n"
"a.b(param1=1);\n"
"a.b(param1=1, param2=2);")
result = re.sub(regex, r"\g<0>.c()", s)
if result:
print (result)
输出
a.b().c();
a.b(param1=1).c();
a.b(param1=1, param2=2).c();
使用PyPi regex module匹配平衡括号:
a\.b(\((?>[^()]++|(?1))*\))
模式匹配:
a\.b
匹配.b
(
捕获第 1 组
\(
匹配(
(?>
原子组(无回溯)
[^()]++
匹配除 (
或 )
之外的任何字符的 1+ 次出现
|
或者
(?1)
递归第一个子模式(组 1)
)*
关闭群组并可选择重复
\)
匹配)
)
关闭第一组
Regex demo | Python demo
import regex
pattern = r'a\.b(\((?>[^()]++|(?1))*\))'
strings = [
"a.b();",
"a.b(param1=1);",
"a.b(param1=1, param2=2);",
"a.b(param1=d(abc=\"123\"));"
]
for s in strings:
m = regex.match(pattern, s)
if m:
print(f"m.group().c()")
输出
a.b().c()
a.b(param1=1).c()
a.b(param1=1, param2=2).c()
a.b(param1=d(abc="123")).c()
【讨论】:
\([^()]*\)
假定第一个右括号是正确的。有没有办法确保捕获正确的右括号?例如对于输入 a.b(param1=d(abc="123"))
。使用建议的正则表达式,它将替换不正确的a.b(param1=d(abc="123").c())
的输入。预期的替换字符串应该是a.b(param1=d(abc="123")).c()
@learningMyWayThru 如果要匹配平衡括号,则必须使用支持递归的PyPi regex module。查看此模式 a\.b(\((?>[^()]++|(?1))*\))
regex101.com/r/lNXtKK/1 并查看 this example code 如何使用它
感谢您的详细解释。我正在使用此正则表达式替换以不同方式缩进的文件中的字符串。因此,上面的正则表达式适用于字符串在一行中但在有新行时不起作用。我尝试使用regex.match(pattern, s, flags=DOTALL)
让它忽略换行符,但无济于事。
@alwaysAStudent 看到这个Python demo
我认为上面链接的 Python 演示有效。非常感谢!!!!【参考方案2】:
这个怎么样:
模式:(a\.b\(.*?\))
替换:\1.c()
结果:
a.b(param1=1).c();
a.b(param1=1, param2=2).c();
a.b().c();
https://regex101.com/r/VwxWR3/1/
【讨论】:
以上是关于使用正则表达式保留中间字符串的主要内容,如果未能解决你的问题,请参考以下文章