2009-06-09 5 views
9

Apparemment, une implémentation de la sortie csv tronque quelque part les séparateurs de champs de droite sur la dernière ligne et seulement la dernière ligne du fichier lorsque les champs sont NULL.Dites à csv.reader de dire quand il est sur la dernière ligne

csv Exemple d'entrée, les champs « c » et « d » sont nullable:

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

quelque chose comme le script ci-dessous, comment puis-je savoir si je suis sur la dernière ligne, donc je sais comment gérer il convient?

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

Notez que ce que vous avez posté n'est pas CSV. CSV signifie "Comma Sepaerated Values" - le séparateur DOIT être une virgule. –

+6

La plupart des implémentations CSV vous permettent de spécifier un autre caractère comme séparateur –

+0

@Neil: hein? "Le format CSV (Comma Separated Values) est le format d'importation et d'exportation le plus commun pour les feuilles de calcul et les bases de données Il n'y a pas de" standard CSV "[..] Pourtant, les délimiteurs et les caractères de citation assez similaire que. [..] " – SilentGhost

Répondre

13

Fondamentalement, vous savez que vous avez plus après que vous avez épuisé. Vous pouvez donc envelopper l'itérateur reader, par ex. comme suit:

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

et changer votre code:

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

etc.

+1

Je suis surpris 'itertools' n'a pas quelque chose comme ça. C'est un cas d'utilisation qui reste récurrent. –

0

apparaissent juste la ligne à la longueur de l'en-tête:

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

Ne pourriez-vous juste attraper l'erreur lorsque le lecteur csv lit la dernière ligne dans un

essayez: ... faites vos affaires ici ... sauf: StopItération

condition?

Voir le code python suivant sur stackoverflow pour un exemple de la façon d'utiliser l'essai: catch: Python CSV DictReader/Writer issues

+0

ne vous dira pas quand vous êtes sur la dernière ligne, seulement vous le dira après avoir passé la dernière ligne. –

+1

Je relis votre question, et vous avez raison, ce n'est pas ce que vous demandez - vous voulez un moyen de traiter la dernière ligne. Pourquoi ne pouvez-vous pas utiliser la solution de John Machin fournie ci-dessous? –

2

Si vous avez une attente d'un nombre fixe de colonnes dans chaque ligne, alors vous devriez être sur la défensive contre:

(1) ANY ligne étant plus courte - par exemple un rédacteur (SQL Server/Query Analyzer IIRC) peut omettre les NULL de fin au hasard; les utilisateurs peuvent manipuler le fichier en utilisant un éditeur de texte, y compris en laissant des lignes vides.

(2) ANY ligne étant plus longue - par ex. les virgules ne sont pas correctement citées.

Vous n'avez pas besoin d'astuces. Juste une ancienne si test dans votre boucle de la ligne de lecture:

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

Je suis d'accord mais la source de ces données refuse/est trop incompétent pour m'envoyer correctement les données formatées. Je n'ai pas d'autre choix que de gérer ses bizarreries moi-même. –

+0

Oui, vous devez gérer vous-même ses bizarreries et je signale simplement que plus de bizarreries que de "champs manquants dans la dernière ligne" doivent être vérifiées en général ET elles peuvent être vérifiées simplement sans code fantaisie - je ne sais pas Comprenez votre "mais". –

0

Si vous utilisez for row in reader:, il va juste arrêter la boucle après le dernier élément a été lu.

1

si vous voulez obtenir exactement la dernière ligne essayez ce code:

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

Si vous voulez continuer à travailler avec les valeurs de la ligne, procédez comme suit:

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

Je suis conscient qu'il est une vieille question, mais j'ai trouvé une réponse différente de celles présentées.L'objet reader incrémente déjà l'attribut line_num pendant que vous le parcourez. Puis j'obtiens le nombre total de lignes au début en utilisant row_count, puis je le compare avec le 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 
Questions connexes