首页 > 解决方案 > 通过 PyCharm 中的正则表达式搜索和替换操作注释掉特定的 Python 代码

问题描述

我正在尝试使用 PyCharm 的“替换文件”功能注释掉特定出现的代码。

具体来说,我希望将以下内容注释掉:

if TYPE_CHECKING:
    from foo import bar
    from x import y

所以可以替换为:

#if TYPE_CHECKING:
#    from foo import bar
#    from x import y

我需要这个,因为我正在使用 来检查循环依赖关系pydeps,在撰写本文时,它似乎没有忽略 TYPE_CHECKING 保护下的导入的选项。手动注释掉这些对于我正在从事的项目来说很乏味。

现在我正在使用这个正则表达式,它符合预期:

(^if TYPE_CHECKING:\n)(^\s+from.?)+

我正在尝试使用以下方法替换它:

#$1#$2

我没想到这会起作用,因为我认为 $2 应该只匹配第二组的第一次出现。

if TYPE_CHECKING:另一种方法是简单地替换以或\s+from.+\n单独使用开头的每一行,例如:

(^if TYPE_CHECKING:\n|^\s+from.+\n)+

然后简单地替换为$1. 只要空格前面没有其他“来自”导入,就可以使用。但是,这也替换了注释中的出现或已经注释掉的代码(我知道这可能被认为是不好的做法,但我正在寻找一种方法来使这项工作更加稳健)。

有人对方法有建议吗?

标签: pythonregexpycharmcommentsmultiline

解决方案


一个选项(如果支持)可以使用\G锚。

在替换使用 # 后跟使用完整匹配#$0

(?:^if TYPE_CHECKING:\R|\G(?!\A)^[^\S\r\n]*(?: from .*)?(?:\R|$))

模式匹配:

  • (?:非捕获组
    • ^if TYPE_CHECKING:\Rif TYPE_CHECKING:从行首匹配和换行
    • |或者
    • \G(?!\A)在上一个匹配的末尾断言位置,而不是在字符串的开头
    • ^[^\S\r\n]*从行首匹配不带换行符的可选空格
    • (?: from .*)?可以选择将一行与 from 匹配(如果存在空行,则越过空行)
    • (?:\R|$)匹配换行符或断言行尾
  • )关闭非捕获组

正则表达式演示

输出

#if TYPE_CHECKING:
#    from foo import bar
#    from x import y

使用代码的选项:

您可以匹配所有以空格和 from 开头的行,并将字符串的所有开头替换为 #。

^if TYPE_CHECKING:(?:\n\s*from .*)*

模式匹配:

  • ^字符串的开始
  • if TYPE_CHECKING:从字面上匹配
  • (?:非捕获组作为一个整体重复
    • \n\s*from .*匹配换行符、可选的空白字符、匹配from 和行的其余部分
  • )*关闭非捕获组

正则表达式演示

例如

import re

pattern = r"^if TYPE_CHECKING:(?:\n\s*from .*)*"

s = ("if TYPE_CHECKING:\n"
            "    from foo import bar\n"
            "    from x import y")

res = re.sub(pattern, lambda x: re.sub(r"^", "#", x.group(), 0, re.MULTILINE), s)
print(res)

输出

#if TYPE_CHECKING:
#    from foo import bar
#    from x import y

推荐阅读