在awk 中,/start/, /end/ 范围正则表达式打印找到/start/ 的整行,包括找到/end/ 模式的整行。它是一个有用的构造,已被 Perl、sed、Ruby 和其他人复制。
要在 Python 中执行范围运算符,请编写一个类来跟踪上一次调用 start 运算符直到 end 运算符的状态。我们可以使用正则表达式(如awk 所做的那样),或者可以将其修改为任何返回True 或False 状态的数据行。
鉴于您的示例文件,您可以这样做:
import re
class FlipFlop:
''' Class to imitate the bahavior of /start/, /end/ flip flop in awk '''
def __init__(self, start_pattern, end_pattern):
self.patterns = start_pattern, end_pattern
self.state = False
def __call__(self, st):
ms=[e.search(st) for e in self.patterns]
if all(m for m in ms):
self.state = False
return True
rtr=True if self.state else False
if ms[self.state]:
self.state = not self.state
return self.state or rtr
with open('/tmp/file') as f:
ff=FlipFlop(re.compile('b bb'), re.compile('d dd'))
print ''.join(line if ff(line) else "" for line in f)
打印:
bbb bb b
ccc cc c
ddd dd d
这保留了逐行读取的文件,具有在其他语言中看到的/start/,/end/ 正则表达式的灵活性。当然,你可以对多行字符串做同样的方法(假设命名为s):
''.join(line+"\n" if ff(line) else "" for line in s.splitlines())
习惯上,在 awk 中,您可以使用标志获得与触发器相同的结果:
$ awk '/b bb/{flag=1} flag{print $0} /d dd/{flag=0}' file
你也可以在 Python 中复制它(用更多的词):
flag=False
with open('file') as f:
for line in f:
if re.search(r'b bb', line):
flag=True
if flag:
print(line.rstrip())
if re.search(r'd dd', line):
flag=False
也可以与内存字符串一起使用。
或者,您可以使用多行正则表达式:
with open('/tmp/file') as f:
print ''.join(re.findall(r'^.*b bb[\s\S]*d dd.*$', f.read(), re.M))
Demo and explanation
但这需要将整个文件读入内存。由于您声明字符串 已 已读入内存,因此在这种情况下这可能是最简单的:
''.join(re.findall(r'^.*b bb[\s\S]*d dd.*$', s, re.M))