如何循环并捕获Python文件的某些部分
我有以下形式的日志文件:如何循环并捕获Python文件的某些部分,python,python-3.x,Python,Python 3.x,我有以下形式的日志文件: SITE_COUNT: 11 PRB_CARD: 108 PRB_FACILITY: LEHI PROCESS_ID: 88AFX TEMP: 0 DATA_SET_ID: _P9kTbjdptOyonKO_ START_DATETIME: 05/01/2020 03:06:24 LOT: 0522072.0 . . . + 1 1588323984 1NA:0NN { Head(1) Site(0) (X,Y)=(-4,16) VALID_COUNT 712 *Z
SITE_COUNT: 11
PRB_CARD: 108
PRB_FACILITY: LEHI
PROCESS_ID: 88AFX
TEMP: 0
DATA_SET_ID: _P9kTbjdptOyonKO_
START_DATETIME: 05/01/2020 03:06:24
LOT: 0522072.0
.
.
.
+ 1 1588323984 1NA:0NN
{
Head(1) Site(0) (X,Y)=(-4,16)
VALID_COUNT 712
*Z
SITE:PARAM_SITE:N3P3
SITE:PROCESS_DURATION:81
1000:1665.67:VALID
.
.
1007:12.0638:VALID
1011:27.728:VALID
.
.
NUM_REGISTERS 712
NUM_VALID 6787
NUM_TESTED 6787
}
.
.
.
+ 2 1585959359 1NA:0NN
{
Head(1) Site(0) (X,Y)=(-2,4)
VALID_COUNT 583
*Z
SITE:PARAM_SITE:N2N3
SITE:PROCESS_DURATION:286
1003:10.0677:VALID
.
.
.
FINISH_ETIME: 1588324881
正如您从示例中看到的,该文件以一个部分开头,该部分的标题为PRB_CARD、PRB_FACILTY。这些头文件通常位于每个文件的前50行中,因此我有一个列表压缩,它只捕获文件的前50行,并将它们输入到字典中,从字典中捕获头部分所需的键值对
我现在的问题是每个标题(x)站点(x)部分下的行。每个头部(x)部分有多条线,通常大约有800条线。我需要捕获每个部分并将它们放在一个表中,让我的脚本移动到下一个部分并捕获它们。每个头部(x)部分需要单独捕获
我怎样才能做到这一点?您可以尝试使用正则表达式拆分:
import re
headSections = re.split(r"^Head\(\d+\) Site\(\d+\).*$", log, flags=re.MULTILINE))
这将创建一个由这些标题行划分的文本节列表,同时删除标题行。如果还想保存标题行,可以将整个正则表达式放在括号中
或者,如果文件太大,无法一次全部读入内存,则可以使用上面的正则表达式检查是否已输入新节:
for line in logFile:
if re.match(r"^Head\(\d+\) Site\(\d+\).*$", log, flags=re.MULTILINE):
# start new section
else:
# add to existing section
有几种懒读文件的方法。可以使用seek操作向后移动当前文件位置。我更喜欢避免额外的操作系统调用,所以方法类似于。您创建了一个惰性迭代器(生成器),该迭代器保持读取所有行的缓冲区,将文件包装为每次读取一个部分。这里的Lazy意味着当调用yield时,函数停止读取文件,直到再次调用为止
def read_section(f):
buffer = []
while True:
line = f.readline()
if line == ""
# EOF
break
# Can do better here probably
if "Head" in line and "Site" in line:
# return current buffer and start packing the next
yield buffer
buffer = [line]
else:
buffer.append(line)
# when finished file return last buffer
yield buffer
我提到的另一个选项是使用seek,显然在python 3中,您只能引用文件的开头进行seek,因此我使用tell来查找当前位置
def read_section(f):
buffer = []
line = f.readline()
while line != "":
# Checking buffer not empty to check if it is first header we are encountering
if "Head" in line and "Site" in line and buffer:
# Unread last line assuming utf8
f.seek(f.tell() - len(l.encode('utf-8')))
return buffer
buffer.append(f.readline())
if line == ""
break
return buffer
更新:这里是原始想法的重新设计版本,使用一个类和一种稍微不同(我希望更干净)的方法来解析数据 假设:
Site count is 2
Processing site 0
Processing site 1
Finished processing.
The headers are ['PRB_CARD: 108', 'PRB_FACILITY: LEHI']
Site 0 data is ['1000:1665.67', '1007:12.0638', '1011:27.728']
Site 1 data is ['1003:10.0677']
代码:
输入是:(注意第一行中的站点计数!)
你能澄清一下到目前为止你都做了些什么吗?你的问题到底是什么?这样我就可以对一个包含一个标题(x)部分下的行的列表进行说明。我的问题是,如何重置列表以从下一个Head(x)部分加载下一组数据。我想分别加载每个头部(x)部分下的每组线。希望有一个列表在点击下一个Head(x)部分@jdaz后自动重置,你说的“重置列表”是什么意思?你试过我上面的第一个例子吗?如果我能正确理解你在找什么,这对你应该有用。对不起,过去5个小时我一直在开会。我还没试过。。。虽然我经常对使用正则表达式犹豫不决,因为在pythonyway上执行列表理解中的重新匹配操作有多慢?您希望理解做什么?可能有一种方法可以通过理解来拆分部分,但如果这就是您所需要的,那么最好使用
re.split
。我认为这将解析标题的逻辑与解析站点数据的逻辑分离开来,我认为,这正是您的导师的想法;)等等,哪个函数只捕获中间部分?中间部分是指包含所有有效部分sbtw的部分,文件本身是一个zip文件,所以它的内容是二进制的。我也已经捕获了我需要的标题。我只需要站点部分下的数据。对于每个部分,只有包含有效内容的行。cide abive演示了如何检测每个部分的开始和结束位置。它使用这样一个事实,即每个站点节都以“{”开头,以“]”结尾。因此,capture_headers(f)读取行,直到遇到第一行{这表示头的结束。当然,在capture_头中发生的事情取决于应用程序,是的,我意识到您已经完成了该任务,但我想显示可运行的代码。为了继续…我现在将保留您的解决方案,因为我没有时间阅读它。这可能更适合于更大的文件。我认为与我的导师讨论过,由于文件通常最多500KB,我决定将这些行加载到一个列表中。然后,我使用一些元组逻辑来查找这些headesr和其他部分的范围,并对它们进行处理。当我不在项目死线时,我会回到这个问题。顺便说一句,我已经有一个包含所有行的列表
import re
# Define a class
class Parse():
headers = []
site_data = []
def __init__(self, f):
self.f = f
# Capture the number of sites in the file.
self.readline()
m = re.match(r'SITE_COUNT: (\d+)', self.line)
if m:
self.site_count = int(m.group(1))
print('Site count is', self.site_count)
else:
raise Exception('Invalid input file format')
self.headers = self.capture_headers()
for i in range(self.site_count):
print('Processing site', i)
self.site_data.append(self.capture_site())
print('Finished processing.')
def capture_headers(self):
headers = []
while self.readline():
if self.line.startswith('{'):
break
if self.line.startswith('PRB_'):
headers.append(self.line)
return headers
def capture_site(self):
pat = re.compile('(\d+:\d*\.\d*):VALID')
data = []
while self.readline():
if self.line.startswith('}'):
break
m = pat.match(self.line)
if m:
data.append(m.group(1))
return data
def get_headers(self):
return self.headers
def get_site_count(self):
return self.site_count
def get_site_data(self, i):
return self.site_data[i]
def readline(self):
self.line = f.readline().rstrip('\n\r')
return not self.line.startswith('FINISH_ETIME:') # Returns False at the end
# Run against the (slightly modified) data:
f = open('data.log')
p = Parse(f)
print('The headers are', p.get_headers())
for i in range(p.get_site_count()):
print('Site', i, 'data is', p.get_site_data(i))
SITE_COUNT: 2
PRB_CARD: 108
PRB_FACILITY: LEHI
PROCESS_ID: 88AFX
TEMP: 0
DATA_SET_ID: _P9kTbjdptOyonKO_
START_DATETIME: 05/01/2020 03:06:24
LOT: 0522072.0
.
.
.
+ 1 1588323984 1NA:0NN
{
Head(1) Site(0) (X,Y)=(-4,16)
VALID_COUNT 712
*Z
SITE:PARAM_SITE:N3P3
SITE:PROCESS_DURATION:81
1000:1665.67:VALID
.
.
1007:12.0638:VALID
1011:27.728:VALID
.
.
NUM_REGISTERS 712
NUM_VALID 6787
NUM_TESTED 6787
}
.
.
.
+ 2 1585959359 1NA:0NN
{
Head(1) Site(1) (X,Y)=(-2,4)
VALID_COUNT 583
*Z
SITE:PARAM_SITE:N2N3
SITE:PROCESS_DURATION:286
1003:10.0677:VALID
.
.
.
}
FINISH_ETIME: 1588324881