【问题标题】:How to remove multiline text from matching strings?如何从匹配的字符串中删除多行文本?
【发布时间】:2020-11-19 02:56:32
【问题描述】:

我有以下 sn-p 我想用正则表达式(或其他方法)完全删除。

# ---------------------------------------------------------------------------------------------------------------------
# MODULE PARAMETERS
# These are the variables we have to pass in to use the module specified in the terragrunt configuration above
# ---------------------------------------------------------------------------------------------------------------------

是否有语法告诉匹配删除两个匹配之间的所有内容?

看起来应该很容易做到,但由于某种原因,我只能找到一个正则表达式,通过此代码提取 第一个和最后一个匹配项。我已经尝试了这个正则表达式的许多排列,但无法让它工作。

...
re.sub(r'# --*[\S\s]*---', '', lines[line])
...

这个regex tool 说我的正则表达式应该可以工作。

编辑:

我有兴趣匹配的文本一次被读取一行。

...
for the_file in files_to_update:
    with open(the_file + "/the_file", "r") as in_file:
        lines = in_file.readlines()

随后被迭代。上面的 sn-p 就是在这个循环中发生的。

for line in range(len(lines)):

【问题讨论】:

  • 什么是lines[line]?它是否包含您问题中显示的所有文本?
  • 我已经更新了问题中的语法,但仍然得到相同的结果
  • @AhmedAbdelhameed 它基本上是一次循环遍历一个文件。让我添加一些关于这部分的更多信息。
  • @jmreicha 这就是我的怀疑。如果它只包含一行,您如何期望找到跨越多行的匹配在一行中?试试re.sub(r'# --*[\S\s]*?---$', '', TheWholeText)
  • @AhmedAbdelhameed 嗯,是的,好点 :) 可能需要跟踪比赛并写一些东西来消除比赛之间的界限?

标签: python regex comments


【解决方案1】:

为什么不把字符串函数和一个小函数一起使用呢?

data = """
# ---------------------------------------------------------------------------------------------------------------------
# MODULE PARAMETERS
# These are the variables we have to pass in to use the module specified in the terragrunt configuration above
# ---------------------------------------------------------------------------------------------------------------------

foo
# some other comment
bar

"""

def remover(block):
    remove = False

    for line in block.split("\n"):
        if line.startswith("# ---"):
            remove = not remove
        elif not remove:
            yield line

cleaned = [line for line in remover(data)]
print(cleaned)

这会产生

['', '', 'foo', '# some other comment', 'bar', '', '']

【讨论】:

  • 我认为这可行,但我担心可能会失去其他 cmets。
  • @jmreicha:是的。
  • @jmreicha:用一个小功能改变了它。
【解决方案2】:

您应该将文件读入单个变量,以便能够在其上运行正则表达式,该正则表达式可以匹配多行文本。

你可以使用

with open(filepath, 'r') as fr:
  with open(filesavepath, 'w') as fw:
    fw.write( re.sub(r'^# -+(?:\n# .*)*\n# -+$\n?', '', fr.read(), flags=re.M) )

查看Python demoregex demo

这里,fr 是您读取的文件的句柄,fw 是您正在写入的文件的句柄。 re.sub 的输入是fr.read(),这个方法抓取整个文件内容并传递给正则表达式引擎。

正则表达式的意思是:

  • ^ - 一行的开始(由于re.M
  • # -+ - #,空格,然后是一个或多个连字符
  • (?:\n# .*)* - 0 次或多次重复换行符、#、空格、直到行尾的任何文本
  • \n - 换行符
  • # -+$ - #、空格、一个或多个连字符和行尾
  • \n? - 可选换行符。

删除 cmets 的非正则表达式方法是逐行读取,检查一行是否以 # --- 开头并设置一个标志,以检查我们是否在注释内:

for line in fr:
    if line.startswith('# ---'):
        flag = not flag
        continue
    if flag:
        lines.append(line)
        
print("\n".join(lines))

this Python demo

【讨论】:

  • 正在删除文本。我稍后在脚本中使用了一些逻辑,这些逻辑依赖于每一行作为解析列表,我想不出一个好的解决方法。
  • @jmreicha 如果您确定每个开头的# --- 行都有一个结尾,您可以编写一些逻辑来逐行遍历,一旦找到“开头行”,您删除/忽略它以及以下行,直到找到“结束行”。或者,您仍然可以使用此答案中的模式一次删除所有不需要的行,然后然后将结果拆分为多行以进行进一步处理。
  • 这可行,但我必须在 continue 语句上方添加另一个 lines.append(line) 以使其捕获第一个和最后一个 cmets。如果在最初的问题中不清楚,我们深表歉意。
猜你喜欢
  • 2021-11-15
  • 2021-11-10
  • 1970-01-01
  • 2015-12-25
  • 2022-10-15
  • 1970-01-01
  • 2017-02-12
  • 2013-02-22
  • 1970-01-01
相关资源
最近更新 更多