Comment puis-je analyser efficacement un fichier CSV en Perl?

je travaille sur un projet qui implique l'analyse d'un grand fichier csv formaté en Perl et je cherche à rendre les choses plus efficaces.

mon approche a été split() le fichier en premières lignes, puis split() chaque ligne de nouveau par des virgules pour obtenir les champs. Mais ce sous-optimal puisqu'au moins deux passes sur les données sont nécessaires. (une fois à diviser par les lignes, puis une fois de plus pour chaque ligne). Il s'agit d'un très gros fichier, donc réduire le traitement de moitié serait une amélioration significative pour l'ensemble de l'application.

ma question Est, Quel est le moyen le plus efficace dans le temps d'analyser un grand fichier CSV en utilisant seulement des outils intégrés?

note: chaque ligne a un nombre variable de jetons, donc nous ne pouvons pas simplement ignorer les lignes et les diviser par des virgules seulement. De plus, nous pouvons supposer que les champs ne contiendront que des données ASCII alphanumériques (pas de caractères spéciaux ou d'autres trucs). Aussi, je ne veux pas entrer dans le traitement parallèle, bien qu'il puisse travailler efficacement.

modifier

il ne peut s'agir que d'outils intégrés qui expédient avec Perl 5.8. Pour des raisons bureaucratiques, Je ne peux pas utiliser de modules tiers (même hébergés sur cpan)

une autre édition

supposons que notre solution n'est autorisé à traiter les données du fichier une fois qu'il est entièrement chargé en mémoire.

encore une autre édition

je viens de comprendre à quel point c'est stupide la question est. Désolé pour perdre votre temps. Le vote pour la fermer.

23
demandé sur Andy Lester 2010-06-17 23:49:02

6 réponses

La bonne façon de le faire-par un ordre de grandeur, est d'utiliser texte:: CSV_XS. Il sera beaucoup plus rapide et beaucoup plus robuste que tout ce que vous êtes susceptible de faire sur votre propre. Si vous êtes déterminé à utiliser seulement la fonctionnalité de base, vous avez un couple d'options en fonction de la vitesse vs robustesse.

A propos de la vitesse que vous obtiendrez pour pure-Perl est de lire le fichier ligne par ligne et ensuite de diviser naïvement les données:

my $file = 'somefile.csv';
my @data;
open(my $fh, '<', $file) or die "Can't read file '$file' [$!]\n";
while (my $line = <$fh>) {
    chomp $line;
    my @fields = split(/,/, $line);
    push @data, \@fields;
}

ceci échouera s'il y a des champs contiennent des virgules. Une approche plus robuste (mais plus lente) serait D'utiliser le texte::ParseWords. Pour ce faire, remplacer le split avec ceci:

    my @fields = Text::ParseWords::parse_line(',', 0, $line);
43
répondu Michael Carman 2014-04-03 06:41:48

Voici une version qui respecte aussi les citations (par exemple