Preprocese el archivo de datos antes de pandas read_csv
Trabajo con salida de datos de SAP, pero no es CSV, ya que no cita cadenas que contienen su delimitador, ni ancho fijo, ya que tiene caracteres de varios bytes. Es una especie de "ancho fijo" en cuanto a caracteres.
Para ponerlo en pandas, actualmente leo el archivo, obtengo la posición de delimitadores, corté cada línea alrededor de los delimitadores y luego lo guardé en un CSV adecuado que puedo leer sin problemas.
Veo que los pandas read_csv pueden obtener un búfer de archivo. ¿Cómo pasaría mi transmisión directamente a ella, sin guardar un archivo csv? ¿Debo hacer un generador? ¿Puedo obtener la salida csv.writer.writerow sin darle un identificador de archivo?
Aquí está mi código:
import pandas as pd
caminho= r'C:\Users\user\Documents\SAP\Tests\\'
arquivo = "ExpComp_01.txt"
tipo_dado = {"KEY_GUID":"object", "DEL_IND":"object", "HDR_GUID":"object", , "PRICE":"object", "LEADTIME":"int16", "MANUFACTURER":"object", "LOAD_TIME":"object", "APPR_TIME":"object", "SEND_TIME":"object", "DESCRIPTION":"object"}
def desmembra(linha, limites):
# This functions receives each delimiter's index and cuts around it
posicao=limites[0]
for limite in limites[1:]:
yield linha[posicao+1:limite]
posicao=limite
def pre_processa(arquivo):
import csv
import os
# Translates SAP output in standard CSV
with open(arquivo,"r", encoding="mbcs") as entrada, open(arquivo[:-3] +
"csv", "w", newline="", encoding="mbcs") as saida:
escreve=csv.writer(saida,csv.QUOTE_MINIMAL, delimiter=";").writerow
for line in entrada:
# Find heading
if line[0]=="|":
delimitadores = [x for x, v in enumerate(line) if v == '|']
if line[-2] != "|":
delimitadores.append(None)
cabecalho_teste=line[:50]
escreve([campo.strip() for campo in desmembra(line,delimitadores)])
break
for line in entrada:
if line[0]=="|" and line[:50]!=cabecalho_teste:
escreve([campo.strip() for campo in desmembra(line, delimitadores)])
pre_processa(caminho+arquivo)
dados = pd.read_csv(caminho + arquivo[:-3] + "csv", sep=";",
header=0, encoding="mbcs", dtype=tipo_dado)
Además, si pudiera compartir las mejores prácticas: tengo cadenas impares de fecha y hora como esta20.120.813.132.432
que puedo convertir con éxito usando
dados["SEND_TIME"]=pd.to_datetime(dados["SEND_TIME"], format="%Y%m%d%H%M%S")
dados["SEND_TIME"].replace(regex=False,inplace=True,to_replace=r'.',value=r'')
No puedo escribir un analizador porque tengo fechas almacenadas en diferentes formatos de cadena. ¿Sería más rápido especificar un convertidor para hacerlo durante la importación o hacer que los pandas lo hagan en columnas al final? Tengo un problema similar con un código99999999
que tengo que agregar puntos a99.999.999
. No se si yodebe escribir un convertidor o esperar hasta después de la importación para hacer undf.replace
EDITAR -- Data de muestra:
| KEY_GUID|DEL_IND| HDR_GUID|Prod_CD |DESCRIPTION | PRICE|LEADTIME|MANUFACTURER| LOAD_TIME|APPR_TIME | SEND_TIME|
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|000427507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123636|Vneráéíoaeot.sadot.m | 29,55 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.157 |
|000527507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123643|Tnerasodaeot|sadot.m | 122,91 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.141 |
|0005DB50112F9E69E10000000A1D2028| |384BB350BF56315DE20062700D627978|75123676|Dnerasodáeot.sadot.m |252.446,99 |3 |POLAND |20.121.226.175.640 |20121226183608|20.121.222.000.015 |
|000627507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123652|Pner|sodaeot.sadot.m | 657,49 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.128 |
|000727507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83| |Rnerasodaeot.sadot.m | 523,63 |30 | |20.120.813.132.432 |20120813132929|20.120.707.010.119 |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| KEY_GUID|DEL_IND| HDR_GUID|Prod_CD |DESCRIPTION | PRICE|LEADTIME|MANUFACTURER| LOAD_TIME|APPR_TIME | SEND_TIME|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |000827507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123603|Inerasodéeot.sadot.m | 2.073,63 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.127 |
|000927507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123662|Ane|asodaeot.sadot.m | 0,22 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.135 |
|000A27507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123626|Pneraíodaeot.sadot.m | 300,75 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.140 |
|000B27507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83| |Aneraéodaeot.sadot.m | 1,19 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.131 |
|000C27507E64FB29E2006281548EB186| |4C1AD7E25DC50D61E10000000A19FF83|75123613|Cnerasodaeot.sadot.m | 30,90 |30 | |20.120.813.132.432 |20120813132929|20.120.505.010.144 |
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Me ocuparía de otras tablas con otros campos. Todo en esta forma general. Solo puedo confiar en los separadores en el encabezado. También puedo tener encabezados repetidos en los datos. Parece una impresión matricial.