【问题标题】:regex string replacement: omit comma if backref is empty正则表达式字符串替换:如果 backref 为空,则省略逗号
【发布时间】:2016-08-15 19:07:28
【问题描述】:

我想使用一个匹配和替换的正则表达式 + backref 表达式

text = 'a,b,c'text = 'a,b,c,item_1'

text = ''text = 'item_1'

text = 'a'text = 'a,item_1'

  1. 我通常对使用 sed 以及使用 python regex 的解决方案感兴趣。

  2. 特别是,我正在寻找与lineinfile 模块Ansible (python) 一起使用的解决方案。

这是我目前所拥有的(在 Ansible 中):

regexp:   "^(text[ ]*=[ ]*')([^']*)(')"
backrefs: yes
line:     '\1item_1,\2\3'

编辑:如果可能,正则表达式 + 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'

【问题讨论】:

  • a、b 和 c 是否总是单个字母,或者可以是任何字母吗?
  • 在实践中,列表中的项目可以是带有下划线的真实单词,但对于这个问题,让我们保留单个字符。

标签: python regex sed ansible backreference


【解决方案1】:

使用消极的环顾四周,我开发了一个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'"

【讨论】:

    【解决方案2】:

    你可以使用

    ^(text[ ]*=[ ]*')((?:[^',]*(,?)[^']*)?[^']*)(')
    

    参见regexPython 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 之前插入此逗号。如果不是,则不插入逗号。

    更新

    您可以将任务拆分为两个操作:

    或 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

    【讨论】:

    • 感谢第一个答案,我试了一下,发现了另一个需要覆盖的案例:将 text = 'a' 替换为 text = 'a,d'(将其添加到问题中)
    • 没有办法纯粹用正则表达式来做,你需要评估捕获组的内容。原因是您不能在 sed 或 Python re regex 风格中使用条件替换模式。你对可以处理这种情况的 Python 代码感兴趣吗?
    • 我发布了一个 2-regex 解决方案,如果您无法访问直接 Python 代码,它可能对您有用。我还发布了一个基于 Python 的解决方案,展示了如何使用 lamda 完全按照您的需要进行替换。不确定它是否有帮助。
    • 感谢调查。我最感兴趣的是可以在 regex101 上测试的正则表达式(python-regex)解决方案,因为这些解决方案可以很容易地移植到 ansible。不需要任何周围的python代码。
    【解决方案3】:

    这在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'
    

    Code Demo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多