Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

311
Views
Convierta un bytes iterable en un iterable de str, donde cada valor es una línea

Tengo un iterable de bytes , como

 bytes_iter = ( b'col_1,', b'c', b'ol_2\n1', b',"val', b'ue"\n', )

(pero por lo general esto no estaría codificado o disponible de una vez, sino que se suministraría desde un generador, por ejemplo) y quiero convertir esto en una iteración de líneas str , donde los saltos de línea se desconocen por adelantado, pero podrían ser cualquiera de \r , \n o \r\n . Así que en este caso sería:

 lines_iter = ( 'col_1,col_2', '1,"value"', )

(pero de nuevo, solo como un iterable, no para que esté todo en la memoria a la vez).

¿Cómo puedo hacer esto?

Contexto: mi objetivo es pasar el iterable de las líneas str a csv.reader (¿que creo que necesita líneas completas?), Pero estoy interesado en esta respuesta en general.

over 4 years ago · Santiago Trujillo
4 answers
Answer question

0

Usé yield y re.finditer .

La expresión de rendimiento se usa cuando se define una función de generador o una función de generador asíncrono y, por lo tanto, solo se puede usar en el cuerpo de una definición de función. El uso de una expresión de rendimiento en el cuerpo de una función hace que esa función sea una función generadora

Devuelve un iterador que produce objetos de coincidencia sobre todas las coincidencias que no se superponen para el patrón RE en la cadena. La cadena se escanea de izquierda a derecha y las coincidencias se devuelven en el orden encontrado. Los partidos vacíos se incluyen en el resultado.
Si no hay grupos, devuelva una lista de cadenas que coincidan con el patrón completo. Si hay exactamente un grupo, devuelva una lista de cadenas que coincidan con ese grupo. Si hay varios grupos presentes, devuelve una lista de tuplas de cadenas que coinciden con los grupos. Los grupos que no capturan no afectan la forma del resultado.

La expresión regular ([^\r\n]*)(\r\n|\r|\n)? se puede dividir en dos partes para que coincida (es decir, dos grupos). El primer grupo coincide con los datos sin \r y \n , y el segundo grupo coincide con \r , \n o \r\n .

 import re find_rule = re.compile("([^\r\n]*)(\r\n|\r|\n)?") def converter(byte_data): left_d = "" for d in byte_data: # Used to save the previous match result in the `for` loop prev_result = None # Concatenate the last part of the previous data with the current data, # used to deal with the case of `\r\n` being separated. d = left_d + d.decode() left_d = "" # Using `find_rule.finditer` the last value("") will be invalid for match_result in find_rule.finditer(d): i = match_result.group() if not i: # The program comes to this point, indicating that i == "", which is the last matching value left_d, prev_result = prev_result.group(), None continue if prev_result: if prev_result.group(2) is None: # The program goes here, represented as the last valid value matched left_d = prev_result.group() else: # Returns the previous matched value yield prev_result.group() # Save the current match result prev_result = match_result else: yield left_d for i in (converter(iter(( b'col_1,\r', b'\nc', b'ol_2\n1', b'\n,"val;\r', b'ue"\n'))) ): print(repr(i))

Producción:

 'col_1,\r\n' 'col_2\n' '1\n' ',"val;\r' 'ue"\n'
over 4 years ago · Santiago Trujillo Report

0

Use el módulo io para hacer la mayor parte del trabajo por usted:

 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

luego simplemente llame a io.TextIOWrapper(ReadableIterator(some_iterable_of_bytes)) .

over 4 years ago · Santiago Trujillo Report

0

Tal vez me estoy perdiendo algo importante (o sutil) porque algunas de las respuestas votadas parecen un poco más exóticas que esto, pero creo que puedes decodificar y encadenar los bytes y usar itertools.groupby para obtener un generador de cadenas:

 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"']
over 4 years ago · Santiago Trujillo Report

0

Poner @o11c's y @user2357112 apoya las contribuciones de Monica juntas:

 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)

y obtengo:

 ['col_1', 'col_2'] ['1', 'value'] ['Hello', '世界'] []
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!