我想使用一个匹配并替换
的正则表达式+ backref-expression 带有text = 'a,b,c'
的 text = 'a,b,c,item_1'
text = ''
text = 'item_1'
和
text = 'a'
与text = 'a,item_1'
。
我一般对使用sed
但使用python regex的解决方案感兴趣。
特别是,我正在寻找一个与lineinfile({3}}(python)的Ansible模块一起使用的解决方案。
这是我到目前为止(在Ansible中):
regexp: "^(text[ ]*=[ ]*')([^']*)(')"
backrefs: yes
line: '\1item_1,\2\3'
编辑:如果可能,regex + backref-ex对应忽略已存在的item_1
,即"替换"
text = 'item_1'
text = 'item_1'
和
text = 'a,item_1'
text = 'a,item_1'
和
text = 'a,d,x'
与text = 'a,item_1,x'
等
答案 0 :(得分:1)
您可以使用
^(text[ ]*=[ ]*')((?:[^',]*(,?)[^']*)?[^']*)(')
请参阅regex和Python demo。
import re
r = re.compile(r"^(text[ ]*=[ ]*')((?:[^',]*(,?)[^']*)?[^']*)(')")
print(r.sub(r"\1\2\3d\4", "text = 'a,b,c'")) # => text = 'a,b,c,d'
print(r.sub(r"\1\2\3d\4", "text = ''")) # => text = 'd'
我所做的只是插入(?:[^',]*(,?)[^']*)?
子模式以选择性地捕获逗号。如果它出现在字符串中,则在d
之前插入此逗号。如果不是,则不插入逗号。
<强>更新强>:
您可以将任务拆分为两个操作:
^(text\[ \]*=\[ \]*')(\[^'\]+)(')
并替换为\1\2,d\3
^(text\[ \]*=\[ \]*')(')
并替换为\1d\2
。或Python解决方案:
import re
p = re.compile(r'^(text[ ]*=[ ]*\')([^\']*)(\')')
strs = ["text = 'a,b,c'", "text = 'a'", "text = ''"]
print([p.sub(lambda x: x.group(1) + (x.group(2) + ",d" if x.group(2) else "d" ) + x.group(3), s) for s in strs])
请参阅IDEONE demo
答案 1 :(得分:1)
这在sed
(在awk中可能)很难做到,因为sed中没有替换回调功能。
以下回调方法应该在python中运行:
import re
reg = re.compile(r"(\btext *= *)'([^']*)'")
def repl(m):
if len(m.group(2)) == 0:
return m.group(1) + "'d'";
else:
return m.group(1) + "'" + m.group(2) + ",d'"
print(reg.sub(repl, r"text = 'a,b,c'"))
print(reg.sub(repl, r"text = ''"))
print(reg.sub(repl, r"text = 'a'"))
<强>输出:强>
text = 'a,b,c,d'
text = 'd'
text = 'a,d'
答案 2 :(得分:0)
使用负面看,我开发了一个working solution,即使它并不完美:
^(text[ ]*=[ ]*)'(((?!item_1[,]?).)*)'
如果这些正则表达式不包含要添加的项目(即item_1
),则此正则表达式会抓取引号之间的所有项目。然后,backref表达式只是添加了缺少的项目:
\1'item_1,\2'
但是,解决方案并不完美,因为如果列表为空,它仍会导致尾随逗号:
text = '' #text = 'item_1,'
text = 'a' #text = 'item_1,a'
text = 'a,b,c,d' #text = 'item_1,a,b,c,d'
对于我的实际案例,尾随逗号是而不是一个问题。
我通过使用another regex
lineinfile
任务来修复它
regexp: "^(text[ ]*=[ ]*)'(.*[^,])(,?)'"
backrefs: yes
line: "\\1'\\2'"