Cómo usar el módulo csv de Python para dividir datos delimitados por doble tubería

Tengo datos que se parecen a

"1234"||"abcd"||"a1s1" 

Estoy tratando de leer y escribir usando el lector y escritor csv de Python. Como el delimitador del módulo csv está limitado a un solo carácter, ¿hay alguna forma de recuperar datos de forma limpia? No puedo permitirme eliminar las columnas vacías, ya que se trata de un conjunto de datos enormemente masivo para ser procesado en forma de tiempo limitado. Cualquier pensamiento será útil.

La documentación y la experimentación demuestran que solo se permiten delimitadores de un solo carácter.

Como cvs.reader acepta cualquier objeto que admita el protocolo iterador, puede usar la syntax del generador para reemplazar || -s con | -s, y luego alimentar este generador al lector:

 def read_this_funky_csv(source): # be sure to pass a source object that supports # iteration (eg a file object, or a list of csv text lines) return csv.reader((line.replace('||', '|') for line in source), delimiter='|') 

Este código es bastante efectivo ya que opera en una línea CSV a la vez, siempre que su fuente CSV genere líneas que no excedan su RAM disponible 🙂

 >>> import csv >>> reader = csv.reader(['"1234"||"abcd"||"a1s1"'], delimiter='|') >>> for row in reader: ... assert not ''.join(row[1::2]) ... row = row[0::2] ... print row ... ['1234', 'abcd', 'a1s1'] >>> 

Desafortunadamente, el delimitador está representado por un carácter en C. Esto significa que es imposible que sea algo distinto a un solo carácter en Python. La buena noticia es que es posible ignorar los valores que son nulos:

 reader = csv.reader(['"1234"||"abcd"||"a1s1"'], delimiter='|') #iterate through the reader. for x in reader: #you have to use a numeric range here to ensure that you eliminate the #right things. for i in range(len(x)): #Odd indexes will be discarded. if i%2 == 0: x[i] #x[i] where i%2 == 0 represents the values you want. 

Hay otras formas de lograr esto (por ejemplo, se podría escribir una función), pero esto le da la lógica que se necesita.

Si sus datos se parecen literalmente al ejemplo (los campos nunca contienen ‘||’ y siempre están citados), y puede tolerar las comillas, o está dispuesto a cortarlos más tarde, simplemente use .split

 >>> '"1234"||"abcd"||"a1s1"'.split('||') ['"1234"', '"abcd"', '"a1s1"'] >>> list(s[1:-1] for s in '"1234"||"abcd"||"a1s1"'.split('||')) ['1234', 'abcd', 'a1s1'] 

csv solo es necesario si el delimitador se encuentra dentro de los campos, o para eliminar comillas opcionales en los campos