2009-06-09 10 views
9

Aparentemente, alguna implementación de salida csv en algún lugar trunca los separadores de campo de la derecha en la última fila y solo la última fila en el archivo cuando los campos son nulos.Haga que csv.reader diga cuándo está en la última línea

Ejemplo de entrada CSV, los campos de los c "y 'd' son anulables:

a|b|c|d 
1|2|| 
1|2|3|4 
3|4|| 
2|3 

En algo así como la secuencia de comandos a continuación, ¿cómo puedo saber si estoy en la última línea, así que sé cómo manejar ¿apropiadamente?

import csv 

reader = csv.reader(open('somefile.csv'), delimiter='|', quotechar=None) 

header = reader.next() 

for line_num, row in enumerate(reader): 
    assert len(row) == len(header) 
    .... 
+3

Tenga en cuenta que lo que ha publicado no es CSV. CSV significa "valores separados por comas": el separador DEBE ser una coma. –

+6

la mayoría de las implementaciones de csv le permiten especificar un carácter alternativo como el separador –

+0

@Neil: ¿eh? "El formato CSV (valores separados por comas) es el formato de importación y exportación más común para hojas de cálculo y bases de datos. No existe un" estándar CSV "[..]. Sin embargo, mientras que los delimitadores y los caracteres de comillas varían, el formato general es lo suficientemente similar que. [..] " – SilentGhost

Respuesta

13

Básicamente sólo se conoce se le han acabado después se le han acabado. Para que pueda ajustar el iterador reader, p. de la siguiente manera:

def isLast(itr): 
    old = itr.next() 
    for new in itr: 
    yield False, old 
    old = new 
    yield True, old 

y cambiar el código para:

for line_num, (is_last, row) in enumerate(isLast(reader)): 
    if not is_last: assert len(row) == len(header) 

etc.

+1

Me sorprende que 'itertools' no tenga algo como esto. Es un caso de uso que se repite. –

0

Sólo extender la fila a la longitud de la cabecera:

for line_num, row in enumerate(reader): 
    while len(row) < len(header): 
     row.append('') 
    ... 
0

que no podía solo capte el error cuando el lector csv lee la última línea en

intento: ... hacer tus cosas aquí ... excepto: StopIteration

condición?

Véase el siguiente código de pitón en stackoverflow para un ejemplo de cómo utilizar el intento de captura: Python CSV DictReader/Writer issues

+0

no le dirá cuándo está en la última línea, solo le informará después de que haya pasado la última línea. –

+1

Vuelvo a leer tu pregunta nuevamente, y tienes razón, eso no es lo que estás preguntando: quieres una forma de lidiar con la última línea. ¿Por qué no puede usar la solución de John Machin que se proporciona a continuación? –

2

Si usted tiene una expectativa de un número fijo de columnas en cada fila, entonces debería estar a la defensiva contra:

(1) CUALQUIER fila que es más corta - por ejemplo un escritor (SQL Server/Query Analyzer IIRC) puede omitir los NULL finales al azar; los usuarios pueden jugar con el archivo usando un editor de texto, incluyendo dejar líneas en blanco.

(2) CUALQUIER fila siendo más larga, p. comas no citadas correctamente

No necesita ningún truco de fantasía. Sólo un anticuado si la prueba en su bucle fila de lectura:

for row in csv.reader(...): 
    ncols = len(row) 
    if ncols != expected_cols: 
     appropriate_action() 
+0

Acepto, pero la fuente de estos datos se niega/es demasiado incompetente para enviarme datos formateados correctamente. No tengo más remedio que manejar sus peculiaridades yo mismo. –

+0

Sí, usted tiene que manejar sus caprichos usted mismo y solo estoy señalando que se deben revisar en general más peculiaridades que "campos nulos finales perdidos en la última fila" Y se pueden verificar simplemente sin código de fantasía - No lo hago entiende tu "pero". –

0

Si utiliza for row in reader:, se acaba de detener el bucle después del último artículo ha sido leído.

1

si usted quiere conseguir exactamente la última fila prueba este código:

with open("\\".join([myPath,files]), 'r') as f: 
    print f.readlines()[-1] #or your own manipulations 

Si desea seguir trabajando con los valores de la fila, haga lo siguiente:

f.readlines()[-1].split(",")[0] #this would let you get columns by their index 
1

Soy consciente de que es una vieja pregunta, pero se me ocurrió una respuesta diferente a las presentadas.El objeto reader ya incrementa el atributo line_num a medida que lo recorre. Luego obtengo el número total de líneas al principio usando row_count, luego lo comparo con el line_num.

import csv 

def row_count(filename): 
    with open(filename) as in_file: 
     return sum(1 for _ in in_file) 

in_filename = 'somefile.csv' 
reader = csv.reader(open(in_filename), delimiter='|') 

last_line_number = row_count(in_filename) 
for row in reader: 
    if last_line_number == reader.line_num: 
     print "It is the last line: %s" % row 
Cuestiones relacionadas