2010-04-19 8 views
18

Courte question: Comment puis-je détecter automatiquement si un fichier CSV comporte des en-têtes dans la première rangée?Présélection automatique des en-têtes CSV dans un fichier

Détails: J'ai écrit un petit moteur d'analyse CSV qui place les données dans un objet auquel je peux accéder en tant que (approximativement) une base de données en mémoire. Le code original a été écrit pour analyser CSV tiers avec un format prévisible, mais j'aimerais pouvoir utiliser ce code plus généralement. J'essaie de trouver un moyen fiable de détecter automatiquement la présence d'en-têtes CSV, afin que le script puisse décider d'utiliser la première ligne du fichier CSV en tant que clés/noms de colonnes ou commencer à analyser les données immédiatement. Comme tout ce dont j'ai besoin est un test booléen, je pourrais facilement spécifier un argument après avoir inspecté moi-même le fichier CSV, mais je préférerais ne pas le faire (allez à l'automatisation).

J'imagine que je devrais analyser le premier 3 à? lignes du fichier CSV et recherchez un motif quelconque à comparer aux en-têtes. Je vais avoir des cauchemars de trois cas particulièrement mauvaises dans lesquels:

  1. Les en-têtes contiennent des données numériques pour une raison quelconque
  2. Les premières lignes (ou une grande partie du CSV) sont nulles
  3. Il têtes et les données semblent trop semblables pour leur dire à part

Si je peux obtenir une « meilleure estimation » et ont l'analyseur échoue avec une erreur ou cracher un avertissement si elle ne peut pas décider, c'est OK. Si c'est quelque chose qui va coûter énormément cher en termes de temps ou de calcul (et qui prend plus de temps que ce qui est censé me sauver), je vais heureusement abandonner l'idée et recommencer à travailler sur des «choses importantes».

Je travaille avec PHP, mais cela me semble plus une question algorithmique/computationnelle que quelque chose qui est spécifique à l'implémentation. S'il y a un algorithme simple que je peux utiliser, génial. Si vous pouvez me diriger vers une théorie/discussion pertinente, ce serait génial aussi. S'il y a une bibliothèque géante qui traite le langage naturel ou 300 types différents d'analyse, cela ne m'intéresse pas.

+0

Je ne pense pas que vous serez en mesure d'atteindre la «fiabilité» en devinant les en-têtes. Sauf si vos données sont assez cohérentes (par exemple, il s'agit de tous les chiffres et facile à discerner les en-têtes et les données). –

+0

Eh bien tout test doit seulement détecter avec succès un en-tête sur une colonne, et le résultat peut ensuite être appliqué à l'ensemble du fichier. S'il existe un ensemble raisonnable de critères pouvant être appliqués à au moins certains types de données/colonnes, il peut toujours fonctionner la plupart du temps. – cbednarski

Répondre

13

Comme d'autres l'ont souligné, vous ne pouvez pas le faire avec une fiabilité de 100%. Dans certains cas, il est utile d'utiliser la fonction "la plupart du temps". Par exemple, les tableurs dotés d'une fonctionnalité d'importation CSV tentent souvent de s'en rendre compte par eux-mêmes. Voici quelques heuristiques qui tendraient à indiquer la première ligne n'est pas un en-tête:

  • La première ligne comporte des colonnes qui ne sont pas des chaînes ou sont vides
  • Les premières colonnes de ligne ne sont pas tous uniques
  • La première ligne semble contenir des dates ou d'autres formats de données communs (par exemple, xx-xx-xx)
+0

Bonne idée, Nick. Cela me donne quelque chose à travailler. Merci. :) – cbednarski

2

Dans le sens purement abstrait, je ne pense pas qu'il existe une réponse algorithmique à votre question car elle se résume à: "Comment distinguer les donnéesA des donnéesB si je ne sais rien de chacune d'elles?". Il y aura toujours un potentiel pour que dataA soit indiscernable de dataB. Cela dit, je commencerais par le simple et ajouter seulement de la complexité au besoin. Par exemple, si vous examinez les cinq premières lignes, pour une colonne (ou des colonnes) donnée si le type de données des lignes 2-5 est identique mais différent du type de données de la ligne 1, il y a de fortes chances qu'une ligne d'en-tête soit présente (l'augmentation de la taille des échantillons réduit la possibilité d'erreur). Cela permettrait (sorta) de résoudre # 1/# 3 - peut-être lancer une exception si les lignes sont toutes remplies mais les données sont indiscernables pour permettre au programme appelant de décider quoi faire ensuite. Pour # 2, ne comptez pas une ligne comme une ligne à moins et jusqu'à ce qu'elle tire des données non nulles .... cela fonctionnerait dans tout sauf un fichier vide (auquel cas vous frapperiez EOF). Ce ne serait jamais infaillible, mais il pourrait être "assez proche".

1

Cela dépend vraiment de la "généralité" de votre outil. Si les données seront toujours numériques, vous le ferez facilement tant que vous assumez des en-têtes non numériques (ce qui semble être une supposition assez juste). Mais au-delà, si vous ne savez pas déjà quels modèles sont présents dans les données, vous ne pouvez pas vraiment les tester à l'avance.FWIW, En fait, je viens d'écrire un script pour analyser certains trucs de TSV, tous de la même source. L'approche de la source pour les en-têtes/le formatage était si dispersée qu'il était logique de faire en sorte que le script me pose des questions à partir de la ligne de commande pendant l'exécution. (Est-ce un en-tête? Quelles colonnes sont importantes?). Donc, pas d'automatisation, mais permettez-moi de parcourir les ensembles de données sur lesquels je travaille, au lieu d'essayer d'anticiper chaque cas de formatage amusant. De plus, mes réponses sont sauvegardées dans un fichier, je n'ai donc besoin d'être impliqué qu'une seule fois par fichier. Pas idéal, mais efficace.

+0

"... faire que le script me pose des questions depuis la ligne de commande pendant l'exécution." J'ai quelque chose de similaire sur un formulaire web qui accepte aussi le format CSV, et c'est efficace, mais pas glamour. J'aime cependant l'idée de mettre en cache les résultats. Ce pourrait être un bon compromis. – cbednarski

5

Dans le sens le plus général, c'est impossible. Ce fichier csv valide:
Nom
Jim
Tom
Bill

La plupart des lecteurs de csv vont simplement prendre HasHeader en option, et vous permettre de passer dans votre tête si vous voulez. Même dans le cas où vous pensez que vous pouvez détecter, que ce soit des en-têtes de caractères et des données numériques, vous pouvez rencontrer une défaillance catastrophique. Et si votre colonne est une liste de séries BMW?
M

Vous traitera ce mal. Le pire de tout, vous perdrez la meilleure voiture!

0

Si vous CSV a un en-tête comme celui-ci.

ID, nom, courriel, date 1, john, [email protected], 12 janvier 2020

faire ensuite une filter_var (str, FILTER_VALIDATE_EMAIL) sur la ligne d'en-tête échouera. Depuis l'adresse e-mail est uniquement dans les données de la ligne. Vérifiez donc la ligne d'en-tête pour une adresse e-mail (en supposant que votre fichier CSV contient des adresses e-mail).

Deuxième idée. http://php.net/manual/en/function.is-numeric.php Vérifiez la ligne d'en-tête pour is_numeric, très probablement une ligne d'en-tête ne contient pas de données numériques. Mais très probablement une ligne de données aurait des données numériques.

Si vous savez que vous avez des dates dans vos colonnes, la vérification de la ligne d'en-tête pour une date fonctionnerait également.

De toute évidence, vous avez besoin du type de données que vous attendez. J'attends les adresses email.

Questions connexes