我要删除此多行字符串中包含b
的所有行:
aba\n
aaa\n
aba\n
aaa\n
aba[\n\n - optional]
请注意,文件不一定由换行符终止,或者在我想保留的末尾可能会有额外的换行符。
这是预期的输出:
aaa\n
aaa[\n\n - as in the input file]
这是我尝试过的:
import re
String = "aba\naaa\naba\naaa\naba"
print(String)
print(re.sub(".*b.*", "", String)) # this one leaves three empty lines
print(re.sub(".*b.*\n", "", String)) # this one misses the last line
print(re.sub("\n.*b.*", "", String)) # this one misses the first line
print(re.sub(".*b.*\n?", "", String)) # this one leaves an empty last line
print(re.sub("\n?.*b.*", "", String)) # this one leaves an empty first line
print(re.sub("\n?.*b.*\n?", "", String)) # this one joins the two remaining lines
我也尝试过flags=re.M
以及各种先行和后退,但主要问题似乎是:如何在匹配项中删除\n
的第一个或最后一次出现字符串,取决于哪一个存在-如果两个都存在,则不行?
答案 0 :(得分:3)
您可以使用正则表达式或非正则表达式方法:
import re
s = "aba\naaa\naba\naaa\naba"
print( "\n".join([st for st in s.splitlines() if 'b' not in st]) )
print( re.sub(r'^[^b\r\n]*b.*[\r\n]*', '', s, flags=re.M).strip() )
请参见Python demo。
非正则表达式方法"\n".join([st for st in s.splitlines() if 'b' in st])
,使用换行符分割字符串,过滤掉所有没有b
的行,然后将这些行重新合并。
正则表达式方法涉及r'^[^b\r\n]b.*[\r\n]*'
之类的模式:
^
-一行的开头[^b\r\n]*
-除CR,LF和b
之外的0个或多个字符b
-一个b
字符.*
-除换行符以外的任何0+字符[\r\n]*
-0个以上的CR或LF字符。请注意,在此之后,您需要使用.strip()
来消除字符串开头/结尾的多余空格。
单个正则表达式解决方案太麻烦了,我不建议在现实生活中使用它:
rx = r'(?:{0}(?:\n|$))+|(?:\n|^){0}'.format(r'[^b\n]*b.*')
print( re.sub(rx, '', s) )
请参见Python demo。
模式看起来像(?:[^b\n]*b.*(?:\n|$))+|(?:\n|^)[^b\n]*b.*
并且匹配
(?:[^b\n]*b.*(?:\n|$))+
-重复1次或更多次
[^b\n]*
-b
和换行符以外的任意0+个字符b.*
-b
和该行的其余部分(.*
匹配除换行符以外的任何0+个字符)(?:\n|$)
-换行符或字符串结尾|
-或
(?:\n|^)
-换行符或字符串开头[^b\n]*b.*
-一行至少包含一个b
答案 1 :(得分:1)
在调用re.sub()来删除其中带有b的行时,需要考虑以下三种情况:
在第二种情况下,您要删除前面的eol字符以避免创建空行。如果有“ b”,则第三种情况将产生一个空字符串。
正则表达式的贪婪将引入第四种情况,因为不能有任何模式重叠。如果您的最后一行包含“ b”,而其前一行也包含“ b”,则案例#1将消耗前一行的eol字符,因此它不符合检测到最后一行的模式的条件(即eol,然后是文字结尾处的模式)。可以通过将连续匹配的行清除(案例1)作为一个组并将最后一行包括为该组的可选组件来解决。不管剩下的是尾随行(情况2),您要在其中删除前一个eol而不是后一个。
为了管理线条图案.*b.*
的重复,您需要从两部分组成搜索图案:线条图案和多次使用它的列表图案。既然我们已经深入正则表达式,为什么不也使用re.sub()来做到这一点。
import re
LinePattern = "(.*b.*)"
ListPattern = "(Line\n)+(Line$)?|(\nLine$)|(^Line$)" # Case1|Case2|Case3
Pattern = re.sub("Line",LinePattern,ListPattern)
String = "aba\naaa\naba\naaa\naba"
cleaned = re.sub(Pattern,"",String)
注意:此技术也可以与其他分隔符一起使用(例如,用逗号代替eol),但是该字符需要从行模式中排除(例如,([^,]*b[^,]*)
) >