Python re.sub 字符串上的多行

Posted

技术标签:

【中文标题】Python re.sub 字符串上的多行【英文标题】:Python re.sub multiline on string 【发布时间】:2016-02-26 16:12:43 【问题描述】:

我尝试使用标志 re.MULTILINE

我阅读了这些帖子:Bug in Python Regex? (re.sub with re.MULTILINE)、Python re.sub MULTILINE caret match,但它不起作用。 代码:

import re
if __name__ == '__main__':

    txt = "\n\
<?php\n\
/* Multi-line\n\
comment */\n\
$var = 1;\n"
    new_txt = re.sub(r'\/\*[.\n]*?\*\/', '', txt, flags=re.MULTILINE)
    print("\n=========== TXT ============")
    print(txt)
    print("\n=========== NEW TXT ============")
    print(new_txt)

代码输出:

=========== TXT ============

<?php
/* Multi-line
comment */
$var = 1;


=========== NEW TXT ============

<?php
/* Multi-line
comment */
$var = 1;

new_txt不应包含多行注释。 我想获得没有多行注释的 txt。你有什么想法吗?

【问题讨论】:

你需要使用re.S标志而不是re.M,并将点放在字符类之外。 基本上您希望[.\n] 匹配除*/ 之外的任何内容,对吗?为什么不使用[^\*\/]+?这将使\/\*[^\*]*\*\/ 匹配您的多行注释而没有标志。 【参考方案1】:

您需要将re.MULTILINE 替换为re.DOTALL/re.S,并将句点移出字符类之外,点匹配文字.

请注意,re.MULTILINE 仅重新定义了 ^$ 的行为,它们被强制匹配在 的开头/结尾而不是整个字符串。 re.DOTALL 标志重新定义了模式内. 的行为仅在字符类之外。它也开始匹配换行符。

因此,您可以在当前示例中使用的正则表达式:/\*.*?\*/。它将文字/*/\* 匹配,然后.*? 匹配尽可能少的任何符号,直至*/(与\*/ 匹配)。

查看代码演示:

txt = """\n\
<?php\n\
/* Multi-line\n\
comment */\n\
$var = 1;\n"""
new_txt = re.sub(r'/\*.*?\*/', '', txt, flags=re.S)
print("\n=========== TXT ============")
print(txt)
print("\n=========== NEW TXT ============")
print(new_txt)

见IDEONE demo

但是,这不是最好的解决方案,因为在大多数情况下,多行 cmets 很长。最好的是 unrolling-the-loop 技术。上面的正则表达式可以像这样“展开”:

/\*[^*]*(?:\*(?!/)[^*]*)*\*/

见regex demo

【讨论】:

感谢您的出色回应和干净的正则表达式! 仅供参考:此解决方案不支持嵌套的多行 cmets。 @alexroat 如果您需要更好的性能,请使用/\*[^*]*(?:\*(?!/)[^*]*)*\*/

以上是关于Python re.sub 字符串上的多行的主要内容,如果未能解决你的问题,请参考以下文章

python re.sub详解

为啥 re.sub() 在 Python 中默认添加不匹配的字符串?

Python正则替换字符串函数re.sub用法示例

python 替换字符串的方法replace()正则re.sub()

python字符串替换之re.sub()

python 正则表达式re.sub()提取字符串以及去除空格