我有一个不是逐行构建的文件,而是包含在下一行中的不同大小的组。我不会详细介绍,因为它并不重要。我只想说线条在结构上没有任何意义。
我的问题是:是否有一种方法可以逐个元素地逐行读取文件,而不是逐行读取?我很确定不逐行进行单调,但我不必阅读每一行并将其与前一行连接,然后处理它。如果有一种简单的方法可以一次读取每个元素,那么事情会变得更容易。对不起,如果之前有人询问,我真的找不到任何东西。谢谢!
编辑:我将添加一个简单的例子
文件如下所示:
1.00 3 4.3 5.6 2.3 4 12.4 0.5 10.2 1.10 8
5.9 11.2 7.3 1.20 8 0.2 1.2 4.2 11 23.1 4.0
7.3 13 4.4 1.7 0.5 (etc.)
这些组以1.00,1.10,1.20开始(总是增加0.1)
答案 0 :(得分:1)
如果数字不会超过记录中断,那么我认为这可以更简单地完成。这是你的数据。
1.00 3 4.3 5.6 2.3 4 12.4 0.5 10.2 1.10 8
5.9 11.2 7.3 1.20 8 0.2 1.2 4.2 11 23.1 4.0
7.3 13 4.4 1.7 0.5
这是代码。
from decimal import Decimal
def records(currentTime=Decimal('1.00')):
first = True
with open('sample.txt') as sample:
for line in sample.readlines():
for number in line.split():
if Decimal(number) == currentTime:
if first:
first = False
else:
yield record
record = [number]
currentTime += Decimal('0.1')
else:
record.append(number)
yield record
for record in records():
print (record)
这是输出。
['1.00', '3', '4.3', '5.6', '2.3', '4', '12.4', '0.5', '10.2']
['1.10', '8', '5.9', '11.2', '7.3']
['1.20', '8', '0.2', '1.2', '4.2', '11', '23.1', '4.0', '7.3', '13', '4.4', '1.7', '0.5']
编辑:此版本在相同的行上运行,但不假设数字不能跨越记录中断。它使用流I / O.你要改变的主要是数据的大小,当然还有来源。
from decimal import Decimal
from io import StringIO
sample = StringIO('''1.00 3 4.3 5.6 2.3 4 12.4 0.5 10.2 1.10 8 \n5.9 11.2 7.3 1.20 8\n.15 0.2 1.2 4.2 11 23.1 4.0 \n7.3 13 4.4 1.7 0.5''')
def records(currentTime=Decimal('1.00')):
first = True
previousChunk = ''
exhaustedInput = False
while True:
chunk = sample.read(50)
if not chunk:
exhaustedInput = True
chunk = previousChunk
else:
chunk = (previousChunk + chunk).replace('\n', '')
items = chunk.split()
for number in items[:len(items) if exhaustedInput else -1]:
if Decimal(number) == currentTime:
if first:
first = False
else:
yield record
record = [number]
currentTime += Decimal('0.1')
else:
record.append(number)
if exhaustedInput:
yield record
break
else:
previousChunk = chunk.split()[-1]
for record in records():
print (record)
这是输出。
['1.00', '3', '4.3', '5.6', '2.3', '4', '12.4', '0.5', '10.2']
['1.10', '8', '5.9', '11.2', '7.3']
['1.20', '8.15', '0.2', '1.2', '4.2', '11', '23.1', '4.0', '7.3', '13', '4.4', '1.7', '0.5']
答案 1 :(得分:1)
使用自定义标头方法的生成器解决方案。宽松地基于Finding all Amazon AWS Instances That Do Not Have a Certain Tag。
输入:
' 1.00 3 4.3 5.6\n 2.3\n 4 12.4 0.5 10.2 1.10 8 5.9 11.2\n 7.3 1.20 8 0.2 1.2\n 4.2 11 23.1 4.0\n 7.3\n 13 4.4 1.7 0.5'
输出:
['1.00', '3', '4.3', '5.6', '2.3', '4', '12.4', '0.5', '10.2']
['1.10', '8', '5.9', '11.2', '7.3']
['1.20', '8', '0.2', '1.2', '4.2', '11', '23.1', '4.0', '7.3', '13', '4.4', '1.7', '0.5']
来源:
#!/usr/bin/env python3
from contextlib import suppress
from functools import partial
# yields strings from a file based on custom headers
#
# f a file like object supporting read(size)
# index_of_next_header a function taking a string and returning
# the position of the next header or raising
# (default = group by newline)
# chunk_size how many bytes to read at a time
def group_file_by_custom_header(f,
index_of_next_header=lambda buf: buf.index('\n') + 1,
chunk_size=10):
buf = ''
for chunk in iter(partial(f.read, chunk_size), ''):
buf += chunk
with suppress(ValueError):
while True:
pos = index_of_next_header(buf)
yield buf[:pos]
buf = buf[pos:]
if buf:
yield buf
# Pass an empty list to data
def index_of_next_timestamp(buf, data):
def next_timestamp(buf):
next_ts = buf.strip().split(maxsplit=2)
if len(next_ts) < 2:
raise ValueError()
return '{:4.2f}'.format(float(next_ts[0]) + 0.1)
if not data:
data.append(next_timestamp(buf))
pos = buf.index(data[0])
data[0] = next_timestamp(buf[pos:])
return pos
def get_dummy_file():
import io
data = ' 1.00 3 4.3 5.6\n 2.3\n 4 12.4 0.5 10.2 1.10 8 5.9 11.2\n 7.3 1.20 8 0.2 1.2\n 4.2 11 23.1 4.0\n 7.3\n 13 4.4 1.7 0.5'
return io.StringIO(data)
data_file = get_dummy_file()
header_fn = partial(index_of_next_timestamp, data=[])
for group in group_file_by_custom_header(data_file, header_fn):
print(repr(group.split()))
答案 2 :(得分:1)
我不知道为什么以前没有发生这种情况。您可以使用词法扫描程序逐个元素地读取元素。我使用过Python附带的那个,即shlex。它的优点是它可以在流输入上运行,不像一些比较流行的,我明白。这似乎更简单。
from io import StringIO
sample = StringIO('''1.00 3 4.3 5.6 2.3 4 12.4 0.5 10.2 1.10 8 \n5.9 11.2 7.3 1.20 8\n.15 0.2 1.2 4.2 11 23.1 4.0 \n7.3 13 4.4 1.7 0.5''')
from shlex import shlex
lexer = shlex(instream=sample, posix=False)
lexer.wordchars = r'0123456789.\n'
lexer.whitespace = ' '
lexer.whitespace_split = True
from decimal import Decimal
def records(currentTime=Decimal('1.00')):
first = True
while True:
token = lexer.get_token()
if token:
token = token.strip()
if not token:
break
else:
break
token = token.replace('\n', '')
if Decimal(token) == currentTime:
if first:
first = False
else:
yield record
currentTime += Decimal('0.1')
record = [float(token)]
else:
record.append(float(token))
yield record
for record in records():
print (record)
输出是:
[1.0, 3.0, 4.3, 5.6, 2.3, 4.0, 12.4, 0.5, 10.2]
[1.1, 8.0, 5.9, 11.2, 7.3]
[1.2, 8.15, 0.2, 1.2, 4.2, 11.0, 23.1, 4.0, 7.3, 13.0, 4.4, 1.7, 0.5]
答案 3 :(得分:0)
如果是我,我会编写生成器函数包装器以提供所需的详细程度:
def by_spaces(fp):
for line in fp:
for word in line.split():
yield word
def by_numbers(fp):
for word in by_spaces(fp):
yield float(word)
def by_elements(fp):
fp = by_numbers(fp)
start = next(fp)
result = [start]
for number in fp:
if abs(start+.1-number) > 1e-6:
result += [number]
else:
yield result
result = [number]
start = number
if result:
yield result
with open('x.in') as fp:
for element in by_elements(fp):
print (element)