【问题标题】:python search/replace regex with sed-like expressionpython搜索/用类似sed的表达式替换正则表达式
【发布时间】:2018-02-16 09:34:33
【问题描述】:

我想在 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(搜索/替换)命令感兴趣,用于单行(无特殊扩展名)。 用例实际上是允许用户为主机名提供字符串转换(带组)。

有什么想法吗?

【问题讨论】:

  • 其他sed 命令呢?有很多。 g 选项呢?现在这太宽泛了(意味着:必须编写大量代码才能将 sed 表达式转换为搜索和替换 python 表达式)。你想走多远。重写sed.py?还是更简单?
  • @Jean-FrançoisFabre 我更新/简化了问题

标签: python regex sed


【解决方案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-wise 转义的斜杠,所以 parts = [re.sub(r"\\/", "/", p) for p in parts] 应该可以解决问题。

我也不确定你最终会如何处理这些标志,但我想如果你知道你期待什么行为,这并不难。

不过,我要补充一点,实现这样一个工具的样板文件可能比仅仅学习 Python 的 re 要大得多。

【讨论】:

  • / 上拆分将不起作用,因为sed 命令可能在搜索或替换字符串时转义了/
  • @anubhava 是的,我正在考虑这个问题。但这适用于 OP 提供的命令,所以我想这是一个好的开始......
  • 还有:创建组的括号用sed转义,而不是用python re转义。不是微不足道的。
  • @Jean-FrançoisFabre 也是。无论如何,公平地说,我认为在sedre 之间创建一个接口没有任何用处,而且“简单”地学习re 可能会容易得多。
【解决方案2】:

我的第一个想法是将其拆分为 / 并将其作为 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'

【讨论】:

    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 2018-08-22
    • 2021-12-31
    • 1970-01-01
    • 2022-06-10
    • 2019-11-03
    • 2013-06-14
    相关资源
    最近更新 更多