python搜索/替换正则表达式与类似sed的表达式

时间:2017-09-07 15:12:50

标签: python regex sed

我想在Python中实现类似sed的搜索和替换。

现在显然,Python有re模块:

import re
re.sub("([A-Z]+)", r"\1-\1", "123 ABC 456")

但是,我想在单个字符串中指定搜索/替换操作,就像在sed中一样(暂时不考虑任何转义问题):

s/([A-Z]+)/\1-\1/g

我更喜欢这种语法的原因是因为实际的搜索和替换规范是由用户提供的,我认为用户指定单个搜索/替换字符串更简单,而不是模式模板

更新

对sed的s(搜索/替换)命令感兴趣,对于单行(没有特殊扩展名)。 用例实际上是允许用户为主机名提供字符串转换(包含组)。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

我的第一个想法是将其拆分为/并将其作为args传递给re.sub

事实证明这是相当复杂的,因为我非常确定它不是防弹的,所以我以此为出发点。

事情是,如果我们想要处理斜杠,如用反斜杠替换斜杠,该怎么办?那么sed表达式将是

's/\\/\//g'

我必须用没有反冲

之前的斜线拆分它
_, pattern, repl, options = re.split(r'(?<!\\)/', sed)

为了使它更复杂,shash可以在两个反斜杠之前,所以:

_, pattern, repl, options = re.split(r'(?<![^\\]\\)/', sed)

re.sub看起来像

re.sub(pattern, repl, s, count='g' not in options)

Ups,不,在Python中,斜杠不必转义,所以:

re.sub(pattern, re.sub(r'\\/', '/', repl), s, count='g' not in options)
>>> import re
>>> s = r'\some\windows\path'
>>> sed = r's/\\/\//g'
>>> _, pattern, repl, options = re.split(r'(?<![^\\]\\)/', sed)
>>> re.sub(pattern, re.sub(r'\\/', '/', repl), s, count='g' not in options)
'/some/windows/path'

答案 1 :(得分:1)

Python的re只是不支持这种语法。 如果你想拥有这样一个工具,你需要开发自己的API,因此必须解析类似sed的命令并执行相应的re函数。

您可以编写一个函数,在给定类似sed的s/命令的情况下解析它,并返回相应的re函数。 然后可以在任何字符串上使用此返回的函数。

def run_sed_sub(command):
    regex = re.compile(r"(?!=\\)/")    # split on unescaped slashes
    parts = regex.split(command)
    if parts[0] != 's':
        raise ValueError("Not a sub command")

    regex = re.compile(parts[1])
    return lambda s: regex.sub(parts[2], s)

>>> func = run_sed_sub(r"s/Hello/Goodbye/g")
>>> print(func("Hello, world!"))
Goodbye, world!

>>> func = run_sed_sub(r"s/([A-Z]+)/\1-\1/g")
>>> print(func("123 ABC 456"))
123 ABC-ABC 456

有一些前卫案例可能会很难处理,例如换行,但这个想法就在这里。 你可能还想用正常的斜杠替换用sed方式转义的斜杠,所以parts = [re.sub(r"\\/", "/", p) for p in parts]应该可以做到。

我不确定你最后会如何处理旗帜,但我想如果你知道你期待的行为并不是很困难。

尽管如此,我还是补充说,实现这样一个工具的样板可能比学习Python的re要大得多。