Python:搜索和替换,但忽略注释行

时间:2018-09-15 20:10:15

标签: python

我实际上想进行搜索和替换,但忽略我所有的注释行,我也只想替换找到的第一个...

input-file.txt

#replace me
#replace me
replace me
replace me

...类似于:

text = text.replace("replace me", "replaced!", 1) # with max. 1 rep.

但是我不确定如何处理(忽略)这些评论。这样我得到:

#replace me
#replace me
replaced!
replace me

6 个答案:

答案 0 :(得分:1)

如我所见,现有解决方案存在以下一个或多个问题

  • 不完整(例如,要求在行首匹配)
  • 不完整(例如,要求匹配不包含\n
  • 笨拙(例如,looong基于文件的解决方案)

我敢肯定,纯正则表达式解决方案将需要可变宽度的lookbehind,re模块不支持(尽管我认为regex模块可以)。尽管稍作调整,正则表达式仍可以提供一个相当干净的答案。

import re

i = re.search(r'^([^#\n]?)+replace me', string_to_replace, re.M).start()

replaced_string = ''.join([
    string_to_replace[:i],
    re.sub(r'replace me', 'replaced!', string_to_replace[i:], 1, re.M),
])

这个想法是,您找到包含比赛开始位置的第一条未注释的行,然后替换您发现从该行开始'replace me'的第一个实例。正则表达式中的^([^#\n]?)+位表示

  1. ^-查找一行的开头。
  2. ([^#\n]?)+-在匹配表达式的其余部分之前,尽可能少地找到([^#\n]?)
    • ([^#\n]?)-在[^#\n]中查找0或1。
      • [^#\n]-查找不是#\n之外的任何东西。

请注意,我们正在使用原始字符串r''来防止在创建正则表达式时双重转义,例如反斜杠,并且我们正在使用re.M进行跨行搜索休息。

注意,如果您要替换的字符串包含模式\n#,则该行为有点奇怪。在这种情况下,您将不得不替换一个或多个注释行的部分或全部,而这可能不是您想要的。考虑到替代方案存在的问题,我倾向于说替代方案都是错误的方法。

如果这不是您想要的,那么由于不确定如何将它们合并在一起,因此将所有注释行排除在外会变得很奇怪。例如,考虑以下输入文件。

#comment 1
replace
#comment 2
me
replace
me

如果要替换字符串replace\nme,会发生什么?您是否因为\n#comment 2介于两者之间而排除了第一个匹配项?如果您使用第一个匹配项,\n#comment 2会去哪里?它是在更换之前还是之后?更换的多条线是否也一样,以便仍可以夹在中间?你只是删除它吗?

答案 1 :(得分:0)

具有一个标志,用于标记您是否已完成替换。然后仅当该标志为true并且行不是注释时才替换:

not_yet_replaced = True
with open('input-file.txt') as f:
   for l in f:
      if not_yet_replaced and not l.startswith('#') and 'replace me' in l:
          l = l.replace('replace me', 'replaced!')
          not_yet_replaced = False
      print(l)

答案 2 :(得分:0)

我不确定您是否设法将文本从文件中取出,因此您可以这样做

f = open("input-file.txt", "r")
text = f.read()
f.close()

然后我要做的方法是先将文本分成这样的行

lines = text.split("\n")

然后在每一行进行替换,并检查它是否不以“#”开头

for index, line in enumerate(lines):
    if len(line) > 0 and line[0] != "#" and "replace me" in line:
        lines[index] = line.replace("replace me", "replaced!")
        break

然后将线缝在一起。

new_text = "\n".join(lines)

希望这会有所帮助:)

答案 3 :(得分:0)

您可以在第一次出现后使用break,如下所示:

with open('input.txt', 'r') as f:
    content = f.read().split('\n')
    for i in range(len(content)):
        if content[i] == 'replace me':
            content[i] = 'replaced'
            break

with open('input.txt', 'w') as f:
    content = ('\n').join(content)
    f.write(content)

输出:

(xenial)vash@localhost:~/python/stack_overflow$ cat input.txt 
#replace me
#replace me
replaced
replace me

答案 4 :(得分:0)

如果输入文件不是很大,则可以将其作为行列表读入内存。然后遍历行并替换第一个匹配的行。然后将这些行写回到文件中:

with open('input-file.txt', 'r+') as f:
    lines = f.readlines()
    substr = 'replace me'    

    for i in range(len(lines)):
       if lines[i].startswith('#'):
           continue
       if substr in lines[i]:
           lines[i] = lines[i].replace(substr, 'replaced!', 1)
           break
    f.seek(0)
    f.truncate()
    f.writelines(lines)

答案 5 :(得分:0)

最简单的方法是使用多行正则表达式及其sub()方法,并将其计数为1:

import re
r = re.compile("^replace me$", re.M)
s = """
#replace me
#replace me
replace me
replace me
"""
r.sub("replaced!", s, 1)

给予

#replace me
#replace me
replaced!
replace me

在线演示here