![](/img/trans.png)
[英]Python static type hint/check mismatch between Iterable[AnyStr] vs Iterable[str] | Iterable[bytes]
[英]Convert a bytes iterable to an iterable of str, where each value is a line
我有一個可迭代的bytes
,例如
bytes_iter = (
b'col_1,',
b'c',
b'ol_2\n1',
b',"val',
b'ue"\n',
)
(但通常這不會被硬編碼或一次全部可用,而是由生成器提供)並且我想將其轉換為str
行的可迭代,其中換行符在前面是未知的,但可以是\r
中的任何一個, \n
或\r\n
。 所以在這種情況下將是:
lines_iter = (
'col_1,col_2',
'1,"value"',
)
(但同樣,就像一個可迭代的,不是所有的都在 memory 一次)。
我怎樣才能做到這一點?
上下文:我的目標是將 str 行的可迭代傳遞給csv.reader
(我認為需要整行?),但我一般對這個答案感興趣。
使用io
模塊為您完成大部分工作:
class ReadableIterator(io.IOBase):
def __init__(self, it):
self.it = iter(it)
def read(self, n):
# ignore argument, nobody actually cares
# note that it is *critical* that we suppress the `StopIteration` here
return next(self.it, b'')
def readable(self):
return True
然后只需調用io.TextIOWrapper(ReadableIterator(some_iterable_of_bytes))
。
yield 表達式在定義生成器 function 或異步生成器 function 時使用,因此只能在 function 定義的主體中使用。 在函數體中使用 yield 表達式會導致 function 成為生成器 function
(?:\r\n)|(?:\r)|(?:\n)
表示匹配\r
, \n
或\r\n
。
import re
split_rule = re.compile("(?:\r\n)|(?:\r)|(?:\n)")
def converter(byte_data):
left_d = ""
for d in byte_data:
t = split_rule.split(left_d + d.decode())
left_d = ""
last_index = len(t) - 1
for index, i in enumerate(t):
if not i:
continue
if index != last_index:
yield i
else:
left_d = i
else:
if left_d:
yield left_d
for i in (converter(iter((
b'col_1,',
b'c',
b'ol_2\n1',
b',"val;',
b'ue"\n')))
):
print(i)
Output:
col_1,col_2
1,"val;ue"
也許我錯過了一些重要(或微妙)的東西,因為一些贊成的答案似乎比這更奇特,但我認為你可以解碼和鏈接字節並使用itertools.groupby
來獲取字符串生成器:
from itertools import groupby, chain
bytes_iter = (
b'col_1,',
b'c',
b'ol_2\n',
b'1,"val;',
b'ue"\n'
)
def make_strings(G):
strings = chain.from_iterable(map(bytes.decode, G))
for k, g in groupby(strings, key=lambda c: c not in '\n\r'):
if k:
yield ''.join(g)
list(make_strings(bytes_iter))
# ['col_1,col_2', '1,"val;ue"']
將 @o11c 和 @user2357112 放在一起支持 Monica 的貢獻:
import codecs
import csv
import io
def yield_bytes():
chunks = [
b'col_1,',
b'c',
b'ol_2\n1',
b',"val',
b'ue"\n',
b'Hello,'
b'\xe4\xb8',
b'\x96',
b'\xe7',
b'\x95\x8c\n'
b'\n'
]
for chunk in chunks:
yield(chunk)
decoder = codecs.getincrementaldecoder('utf-8')()
def yield_encoded_bytes():
s = None
for bytes in yield_bytes():
s = decoder.decode(bytes, final=False)
if s:
yield s.encode('utf-8')
class ReadableIterator(io.IOBase):
def __init__(self, it):
self.it = iter(it)
def read(self, n):
# ignore argument, nobody actually cares
# note that it is *critical* that we suppress the `StopIteration` here
return next(self.it, b'')
def readable(self):
return True
f = io.TextIOWrapper(ReadableIterator(yield_encoded_bytes()))
for row in csv.reader(f):
print(row)
我得到:
['col_1', 'col_2']
['1', 'value']
['Hello', '世界']
[]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.