Python同时读取文本文件中的3行

2024-04-27 14:11:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个file.txt看起来像这样。你知道吗

testings 1
response 1-a
time 32s

testings 2
response 2-a
time 32s

testings 3
*blank*

testings 4
error

testings 5
response 5-a
time 26s

还有指纹

['testings 1', 'testings 2', 'testings 3', 'testings 4', 'testings 5']     
['response 1-a', 'response 2-a', 'response 5-a']
['time 32s', 'time 20s', 'time 26s']

所以我有一个simpel代码,它打开文件,使用readlines()并查找关键字testingsresponsetime,然后将字符串附加到3个单独的列表中。如file.txt所示,一些testings x要么是*blank*,要么是error,而不是response。我的问题是我需要列表总是有相同的长度。像这样:

 ['testings 1', 'testings 2', 'testings 3', 'testings 4', 'testings 5']
 ['response 1-a', 'response 2-a', '*error*', '*error*', 'response 5-a']
 ['time 32s', 'time 20s', '*error*', '*error*',  'time 26s']

所以我在想,如果可以“同时读3行”并且有一个if语句,其中所有3行都需要有正确的关键字(“be True”),或者在响应和时间列表中插入*error*,以保持长度正确。或者有没有更好的方法让3个列表保持相同的长度?你知道吗

test = []
response = []
time =[]

with open("textfile.txt",'r') as txt_file:
    for line in txt_file.readlines():
        if ("testings") in line:
            test.append(line.strip())    
        if ("response") in line:
            response.append(line.strip())
        if ("time") in line:
            time.append(line.strip())


print (response)
print (test)
print (time)

Tags: intesttxt列表iftimeresponseline
3条回答

文本文件是iterables,这意味着您可以直接在它们上面循环,也可以使用^{} function从它们那里获取另一行。file对象将始终生成文件中的下一行,无论您使用什么方法,甚至在混合技术时也是如此。你知道吗

您可以使用它在for循环中拉入更多行:

with open("textfile.txt",'r') as txt_file:
    for line in txt_file:
        line = line.strip()
        if line.startswith('testings'):
            # expect two more lines, response and time
            response_line = next(txt_file, '')
            if not response_line.startswith('response'):
                # not a valid block, scan forward to the next testings
                continue
            time_line = next(txt_file, '')
            if not time_line.startswith('time'):
                # not a valid block, scan forward to the next testings
                continue
            # valid block, we got our three elements
            test.append(line) 
            response.append(response_line.strip())
            time.append(time_line.strip())

因此,当找到以testings开头的行时,代码会拉入下一行。如果该行以response开头,则会拉入另一行。如果该行以time开头,那么这三行都将附加到数据结构中。如果这两个条件都不满足,则继续执行外for循环并继续读取文件,直到找到另一行testings。你知道吗

额外的好处是,文件永远不会一次性读入内存。文件缓冲保持了这种效率,但是如果不是这样的话,您永远不需要比最后一组列表(有效数据)和当前正在测试的三行所需要的内存更多的内存。你知道吗

旁注:我强烈建议您不要使用三个长度相等的单独列表。您可以使用带有元组的单个列表:

test_data = []
# ... in the loop ...
test_data.append((line, response_line.strip(), time_line.strip()))

然后用这个列表把每个三元组的信息放在一起。您甚至可以使用named tuple

from collections import namedtuple

TestEntry = namedtuple('TestEntry', 'test response time')

# ... in the loop
test_data.append(TestEntry(line, response_line.strip(), time_line.strip()))

此时,test_data列表中的每个条目都是具有testresponsetime属性的对象:

for entry in test_data:
    print(entry.test, entry.response, entry.time)

此代码段执行您正在查找的操作。您可以使用next(txt_file, '')检索下一行,而不必先将文件加载到内存中。然后,只查找包含“testing”的行,然后比较下两行。每当它找到“testing”时,它总是向每个列表添加一个字符串,然而,如果它没有找到“response”或“time”,那么它将在适当的地方插入错误。下面是代码,使用您上面提供的输入。你知道吗

with open("textfile.txt", "r") as txt_file:
     test = []
     response = []
     time = []
     for line in txt_file:
         if "testings" in line:
             test_line = line.strip()
             response_line = next(txt_file, '').strip()
             time_line = next(txt_file, '').strip()
             test.append(test_line)
             if "response" in response_line:
                 response.append(response_line)
             else:
                 response.append("*error*")
             if "time" in time_line:
                 time.append(time_line)
             else:
                 time.append("*error*")

以及输出:

In : test
Out: ['testings 1', 'testings 2', 'testings 3', 'testings 4', 'testings 5']

In : response
Out: ['response 1-a', 'response 2-a', '*error*', '*error*', 'response 5-a']

In : time
Out: ['time 32s', 'time 32s', '*error*', '*error*', 'time 26']

In : len(test), len(response), len(time)
Out: (5, 5, 5)

从答案here

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

with open("textfile.txt",'r') as txt_file:
    for batch in grouper(txt.readlines, 3):
        if ("testings") in batch[0]:
            test.append(line.strip())
        else:
            test.append('error')
        if ("response") in batch[1]:
            response.append(line.strip())
        else:
            response.append('error')
        if ("time") in batch[2]:
            time.append(line.strip())
        else:
            time.append('error')

这假设总是有相同顺序的行,并且文件总是以三行为一批进行组织,即使这只是一个空行。因为它实际上看起来像您的输入文件有一个空白行之间的每一组3您可能需要改变grouper读取批4。你知道吗

相关问题 更多 >