Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何循环并捕获Python文件的某些部分_Python_Python 3.x - Fatal编程技术网

如何循环并捕获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\u COUNT:nnn”的行开始,其中nnn是站点部分的数量
  • 每个站点节前面都有一行以“{”开头,后面是一行以“}”开头
  • 标头和站点数据存储在数组中。更改代码以存储和返回其他数据类型(如dict)中的数据应该很容易
  • 下面代码中的调用Parse(f)创建一个Parse对象,该对象解析整个流f,并公开获取头和捕获的(多个)站点数据的方法。(请参见代码的最后几行)

    对于下面的示例输入数据,输出为:

    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