DLL et CSV
Résolu
Bonjour à tous !
Je suis entrain d'écrire une dll en C# pour faciliter l'utilisation de ce type de fichier. (Je ne peux pas utiliser une dll déjà faite)
Pour le moment je récupère les données de mon csv dans une list et j'essaye ensuite de récupérer une ligne de ma list à l'aide d'un match d'un string que je mets en paramètre.
A la base je voulais récupérer un index que je traiterais dans la fonction GetValue() mais si quelqu'un a une meilleure idée ...
Mes problèmes sont:
- Mon programme récupère seulement une cellule sur deux (et je ne vois pas pourquoi)
- Le match ne fonctionne pas, il passe à true pour toutes les cellules (ou presque) malgrès le regex
- Je souhaiterais enlever "nbColumn" et récupérer les colonnes jusqu'à ce que'il n'y est plus de valeurs ( essayé avec reader.EndOfData mais ça semble uniquement fonctionner avec les lignes )
Ci dessous le code en question :
Merci d'avance :)
Je suis entrain d'écrire une dll en C# pour faciliter l'utilisation de ce type de fichier. (Je ne peux pas utiliser une dll déjà faite)
Pour le moment je récupère les données de mon csv dans une list et j'essaye ensuite de récupérer une ligne de ma list à l'aide d'un match d'un string que je mets en paramètre.
A la base je voulais récupérer un index que je traiterais dans la fonction GetValue() mais si quelqu'un a une meilleure idée ...
Mes problèmes sont:
- Mon programme récupère seulement une cellule sur deux (et je ne vois pas pourquoi)
- Le match ne fonctionne pas, il passe à true pour toutes les cellules (ou presque) malgrès le regex
- Je souhaiterais enlever "nbColumn" et récupérer les colonnes jusqu'à ce que'il n'y est plus de valeurs ( essayé avec reader.EndOfData mais ça semble uniquement fonctionner avec les lignes )
Ci dessous le code en question :
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic.FileIO;
namespace CSV
{
public class CCSV
{
public List<List<string>> Tab;
//Constructeur
public void Load(string path, string separator)
{
Tab = new List<List<string>>(GetCol(path , separator));
}
private List<List<string>> GetCol(string path, string separator) //Recupère le tableau dans une liste
{
List<List<string>> RegExValues = new List<List<string>>();
int nbColumn = 27; //Faire en sorte que nbColumn s'arrete quand il n'y a plus de valeur dans les colonnes!!
int i;
string indexLine = "0";
int count = 0;
try
{
TextFieldParser reader = new TextFieldParser(path);
reader.TextFieldType = FieldType.Delimited;
reader.SetDelimiters(separator);
while (!reader.EndOfData)
{
//Process row
List<string> AllDataLine = new List<string>(reader.ReadFields());
List<string> Line = new List<string>();
for ( i = 0; i < nbColumn; i++)
{
Line.Add(AllDataLine[i]);
i++;
}
if ( AllDataLine[0] != "LigneIndesirable") //Evite l'ajout de la ligne LigneIndésirable + ajoute une cellule "index"
{
indexLine = count.ToString();
Line.Add(indexLine);
count++;
RegExValues.Add(Line);
}
else
{
reader.ReadFields();
}
}
reader.Close();
}
catch (Exception ex)
{
//Gérer les erreur avec loggers
}
return RegExValues;
}
public string GetValue(string MLFB, string ValueName)
{
string result = "";
return result;
}
public int GetIndex(string value)
{
int index = 0;
int result = 0;
foreach (List<string> line in Tab)
{
foreach (string col in line)
{
Match match = Regex.Match(value, col);
if (match.Success)
{
result = index;
}
}
index++;
}
return index;
}
}
}
Merci d'avance :)
24 réponses
Résumé de la discussion
Un développeur C# tente de créer une DLL pour faciliter l’utilisation de fichiers CSV, mais rencontre des problèmes de récupération correcte des colonnes, d’application des regex et de gestion des lignes vides. Plusieurs propositions préconisent de remplacer le compte de nbColumn par une approche compatible CSV, en lisant les lignes avec ReadAllLines et Split, ou en utilisant Linq pour simplifier le flux. D’autres rappellent que modéliser les données sous forme d’objets et concevoir des classes dédiées améliore les performances et la maintenabilité que du parsing brut ligne par ligne.
-
-
Bonjour,
Je n'ai pas eu le temps de regarder ta réponse avant, désolé.
Mais je vois pourquoi ça ne fonctionne pas chez moi.
Je pense mettre mal exprimé (encore une fois) .. Pour la ligne ci dessous :
Mesurande m = test.TrouveMesurande("Current", "BLA-.UH[48]0...E..22");
Ici, tu mets déjà la donnée en regex alors que je pensais mettre une donnée complète du genre :
Mesurande m = test.TrouveMesurande("Current", "BLA-4UH80321EAB22");
Et donc ajouter un "match" ici: Pour faire matcher "BLA-.UH[48]0...E..22" du csv et "BLA-4UH80321EAB22" en entrée
public Mesurande TrouveMesurande(string Nom, string DonneeRegex) { return Datas.FirstOrDefault(d => d.DonneeRegex == DonneeRegex)?.Mesurandes.FirstOrDefault(m => m.Nom == Nom); }
Merci :) -
@TheolitHa oui, il tu dois ajouter une regex là en effet, un truc du genre
d => Regex.IsMatch(DonneeRegex, d.DonneeRegex)
-
@Utilisateur anonymeCa fonctionne ! Merci encore pour toutes tes explications.
-
@TheolitDe rien
-
-
Essaye ça
/// <summary> /// Construit une instance de DonneeTheolit à partir d'un csv /// </summary> /// <param name="Filename"></param> public ImportDonneTheolit(string Filename) { filename = Filename; if (!File.Exists(Filename)) throw new Exception("Fichier introuvable"); if (Path.GetExtension(Filename).ToLower() != ".csv") throw new Exception("Mauvaise extension"); //Lecture du fichier string[] lesLignes = File.ReadAllLines(Filename, Encoding.Default); //Hypothèse 1, les métadatas sont toujours dans les 10 premières lignes List<string[]> metadatas = (from l in lesLignes.Take(10) select l.Split(';') ).ToList(); //les hypothèses 2 et 3 ne sont pas applicables à tous les fichiers //hypothèse 4, le modèle AAAA_XX de la dernière ligne de métadatas permet de générer les prototypes. //dans un premier temps en groupant les entêtes en fonction de XX //dans un seconde temps en en tirerant les prototypes var entetesIndexes = metadatas[9].Select((texte, ind) => new { texte, ind }); List<PrototypeMesurande> prototypes = (from x in entetesIndexes let m = Regex.Match(x.texte, @"^(?<entete>[\w_]+)_(?<numero>\d+)$") where m.Success group new { ind = x.ind, numero = m.Groups["numero"].Value, entete = m.Groups["entete"].Value } by m.Groups["numero"].Value into g select new PrototypeMesurande(metadatas[0][g.First().ind], g.First().ind, g.Select(y => y.entete).ToArray()) ).ToList(); //hypothèse 5, l'index de la colonne MLFB_RegEx change mais son nom reste le même int indexRegex = entetesIndexes.First(x => x.texte == "MLFB_RegEx").ind; //hypothèses 6, la dernière ligne du fichier est a exclure de l'import var import = lesLignes.Skip(10).ToList();//on exclue les 10 premières ligne du fichier import = import.Take(import.Count - 1).ToList();//on exclue la dernière ligne //import des données Datas = (from l in import let split = l.Split(';') select new DonneeTheolit(split[0], split[indexRegex], ToMesurandes(split, prototypes)) ).ToList(); }
-
La récupération des données fonctionne !
Par contre:
public Mesurande TrouveMesurande(string Nom, string DonneeRegex) { return Datas.FirstOrDefault(d => d.DonneeRegex == DonneeRegex)?.Mesurandes.FirstOrDefault(m => m.Nom == Nom); }
Me revoie "null" . (Mes valeurs sont bien dans le tableau.
Est ce que je dois ajouter un 'Regex.Match' pour faire correspondre d.DonneRegex et DonneRegex?
-
-
J'avais bien compris que tu voulais t'en servir.
Et à raison, manifestement.
Mais tes explications initiales étaient trop floues et je n'ai pas vu l'intérêt de la chose.
Bon j'ai pu générer mes prototypes avec ces numéros.
Mais il y'a 2 nouveaux problèmes avec ce fichier.
D'abord la dernière ligne. Une ligne commMLFB_RegExe ça est-elle toujours présente?
Ensuite dans le premier fichier la colonne que tu avais appelées "Données-Regex" était la colonne E. Dans le second, il y a 3 colonnes dont les valeurs y ressemble, O, P et S. Celle qui y ressemble le plus est la O est s'appelle MLFB_RegEx. Est ce bien cette colonne et, s'appelle t elle toujours ainsi?
Question subsidiaire, y a t il toujours une colonne "Nber_of_Variable" (même si j'ai fait sans, ça peut permettre de vérifier)
-
Désolé pour la réponse tardive ( fête oblige, d'ailleurs bonnes fêtes de Pâques s'il y a lieu),
la colonne MLFB_RegExe sera toujours présente mais pas forcement au même endroit (peut être décalé d'une ou deux colonne)
La colonne "Données-Regex" est bien équivalente à "MLFB_RegEx". En effet, il s'agit du nouveau nom de cette colonne, ce sera donc toujours "MLFB_RegEx".
La colonne "Nber_of_Variable" n'est malheureusement pas présente dans la totalité des fichiers . -
-
@Utilisateur anonymeMerci !
Si tu parles de la ligne où il y a la somme du nombre de ligne, oui, elle est encore présente.
-
-
Le 1/03 je t'ai écrit
Bon j'aurais eu d'autres questions, mais j'ai émis des hypothèses (elles sont en commentaire dans le code).
Si elle ne sont pas exactes, faudra me le dire
Et ça n'est que maintenant, parce que volontairement je joue à l'idiot pour te forcer la main, que tu commences à esquisserC’est à dire pas de pattern défini ?
ce qui sous entends qu'au moins une hypothèse n'est pas valable du tout (pas juste qu'il faut l'adapter un peu), mais tu ne le dis toujours pas clairement.
Je n'ai pas accès à tes fichiers (à part 2 morceaux dont je ne sais pas à quel point ils sont représentatifs). Je ne peux pas me faire une idée générale de ce qui pourrait marcher.
Donc quand je te dis "j'ai constaté... je pars sur cette base..." et que c'est faux, c'est toi qui perd du temps à ne pas le dire.
On est bien d'accord que le but c'est que l'opérateur n'ait pas à définir où commence chaque mesurande? (Et je veux une réponse claire)
Dans ce cas il faut trouver quelque chose de reproductible.
Au début, tu parlais des nombres à la fin des entêtes de la ligne 10.
Que tous les 1 correspondent à un mesurande, les 2 au suivant etc...
Est ce que ça, c'est toujours vrai? (Et je veux une réponse claire)
-
Oui, j'avais bien lu, mais le problème est que je voulais réellement partir d'un fichier sous la forme du premier (avec varXXX) Mais j'ai découvert récemment que d'autres fichier n'ont pas la même forme. C'est à dire qu'ils n'ont pas de mots devant chaque Nom de variables , etc ...
Exemple :
Test Name:;;Nom;;;;;;;;;;;;No modification;;;;;Variable_dB;Test;;;Offset;;;
Test Nr:;;123;;;;;;;;;;;;Comments:;;;;;Variable Name;Offset_Modification;;;Offset;;;
Cost Center;;123*;;;;;;;;;;;;Control plan;;;;;Datatyp;1;;;1;;;
Modification date:;;20/03/2021;;;;;;;;;;;;;;;;;Distribution;1;;;1;;;
"Resp; of modif.:";;Moi.;;;;;;;;;;;;;;;;;Unit;mV;;;mV;;;
File Name;;Nom_123;;;;;;;;;;;;;;;;;Lower_limit ;85%;;;85%;;;
File Place;;C:\Temp;;;;;;;;;;;;;;;;;Upper_limit ;85%;;;85%;;;
;;;;;;;;;;;;;;;;;Doc;;Middle_Value_limit (in %);40;;;40;;;
;;;;;;;;;;;;;;;;;No document;;Standard_Dev_limit (in %);10;;;10;;;
Variant;Type;Bla;BlaBla;4;5;6;7;8;9;10;11;12;BlaBlaBla;MLFB_RegEx;Inspection_Plan;Inspection_Plan_Name;Inspection_Plan_Drawing_Index;Inspection_Order;Nber_of_Variable;Nominal_Value_1;Lower_Tol_1;Upper_Tol_1;Nominal_Value_2;Lower_Tol_2;Upper_Tol_2;Remark
ABC;P;BLA-.;UH;[48];0;.;.;.;A;.;.;22;;BLA-.UH[48]0...A..22;DEF-BLA-.UH[48]0...A..22;DEF 0,25 bar;1;DEF-.UH[48]0...A..22-1;2;-6,5;-1,5;1,5;0;-61;61;123
YZ;P;PLA-.;UH;[48];0;.;.;.;B;.;.;22;;PLA-.UH[48]0...B..22;XY-PLA-.UH[48]0...B..22;XY 1 bar;1;XY-.UH[48]0...B..22-1;2;-2,1;-0,9;0,9;0;-18;18;456
J'avais bien compris, mais ayant reçu des informations aux compte gouttes (différents fichiers etc...) c'était un peu trop flou pour moi, pour que je puisse te répondre efficacement. D'ailleurs, je m'en excuse.
Effectivement, le but final est que la personne qui va utiliser cette DLL aura juste à appeler une fonction du genre:
GetValue("La chaine Regex","Le nom du mesurande", "La colonne cherché"); OU GetValue("Regex","Offset", "Upper_Tol");
Au début, tu parlais des nombres à la fin des entêtes de la ligne 10.
Que tous les 1 correspondent à un mesurande, les 2 au suivant etc...
Effectivement, C'est toujours vrai. D'où ma volonté de départ de récupérer ce chiffre.
Chaque mesurande aura un index en ligne 10, sous la forme :
;Nominal_Value_1;Lower_Tol_1;Upper_Tol_1;
Mais en fonction des fichiers, le nom de ces colonnes est amené à changer (en gardant l'index en fin)
Exemple pour un même mesurande:
;Value_1;Upp_Off_1;Lower_Tol_1;
Voilà voilà, j'espère avoir été assez claire cette fois ...
Merci d'avance pour tout.
-
-
Dans ce cas, il faut changer la regex.
Si c'est toujours Variable_ suivit du nom de la variable, alors la regex est@"^Variable_\w+$"
-
OK mais dans tes autres "vrais" fichiers c'est comment?
-
Non ça c’est pas l’hypothèse, c’est le code qui en découle.
L’hypothèse c’est//Hypothèse 2, le nom d'un mesurande est toujours précédé de varXXX
une précision que je n’avais pas faite c’est XXX représente un nombre à trois chiffres.- Est ce que cette hypothèse s’applique au nouveau fichier?
- Voire s’applique t elle tout court (en gros avais tu modifié les noms dans le premier fichier envoyé)?
-
C’est certain commenter ne peut pas fonctionner.
On a besoin de savoir à quelle colonne commence chaque mesurande pour la suite.
Mais comment faudrait il modifier cette hypothèse pour qu’elle soit applicable à ce fichier et au précédent ?
-
Rappel de l'hypothèse:
List<int> indexMesurandes = metadatas[0].Select((texte, ind) => new { texte, ind }).Where(x => Regex.IsMatch(x.texte, @"^var\d+$")).Select(x => x.ind + 1).ToList();
Il faudrait modifier la partie après Where(...) ?
Je pense remplacer le Regex.IsMatch par quelque chose qui permet de sortir le nom des Mesurandes ?
Peut-être en récupérant la première ligne de "lesLignes" ou de "metadatas".
Mais je ne vois pas trop comment faire pour l'adapter à n'importe quel fichier.
-
-
Oui bonne piste.
Que dit l'énoncé de l'hypothèse 2?
Est applicable à ce fichier?
-
Ok, je viens de tester rapidement.
As tu exécuté en pas à pas et espionné les variable pour voir ce qui se passe?
Je ne pense pas.
J'ai cerné d'où vient le problème en quelques instants, et vu le problème en question si tu l'avais fait toi aussi.
Pour progresser savoir débogger est aussi important que savoir coder (p'tet même plus).
Je t'invite donc par commencer à regarder ce qui se passe et revenir me dire ce que tu constates.
-
J'ai regardé avant de demander mais je pense avoir commenté des lignes en trop pour enlever les hypothèses que je ne voulais pas ...
Avec mon erreur, il me manquait les données dans "prototypes".
J'ai donc décommenté ceci:
List<PrototypeMesurande> prototypes = new List<PrototypeMesurande>(); for (i = 0; i < indexMesurandes.Count - 1; i++) { index1 = indexMesurandes[i]; int index2 = indexMesurandes[i + 1]; prototypes.Add(new PrototypeMesurande(metadatas[0][index1], index1, metadatas[9].Skip(index1).Take(index2 - index1).ToArray())); }
Sauf que avec ça , il me manque "indesMesurande" qui est présent dans l'hypothèse 2 (que j'ai commenté).
Donc je remet ça ://Hypothèse 2, le nom d'un mesurande est toujours précédé de varXXX // => on peut extraire l'index de début de chaque mesurande List<int> indexMesurandes = metadatas[0].Select((texte, ind) => new { texte, ind }).Where(x => Regex.IsMatch(x.texte, @"^var\d+$")).Select(x => x.ind + 1).ToList();
Et je m'aperçois que 'indexMesurandes' reste à 0.
Bonne piste ? ou je suis loin ?
-
-
Je suis en déplacement jusqu’au début de la semaine prochaine, je n’ai que ma tablette, et elle ne me permet pas de coder.
Quoiqu’il en soit j’aurais besoin du fichier (anonymisé bien sûr) qui fait planter
-
Ha, je n’ai pas bien vu l’image peut-être.
Et la classe DonneeTheolit?
-
C'était bien ça, merci!
Maintenant je rencontre d'autres problèmes,
Comme :
ou alors: (En utilisant que l'hypothèse 1, pas de données dans la list "m")

J'ai essayé en enlevant les différentes hypothèses mais j'ai soit l'erreur ci-dessus, soit le programme ne me ressort rien (pas de mesurande). Sachant que ce serait l'hypothèse 1 qui m'intéresserait.
Rappel du code:/// <summary> /// Correspond à un relevé pour un mesurande /// </summary> public class Mesurande { public Mesurande(string LeNom, Dictionary<string, double> LesDatas) { Nom = LeNom; Datas = LesDatas; } public string Nom { get; private set; } public Dictionary<string, double> Datas { get; private set; } public override string ToString() { return string.Format("{0}, {1} valeurs", Nom, Datas.Count); } } /// <summary> /// Permet de construire un mesurande à partir d'un fichier /// </summary> class PrototypeMesurande { public PrototypeMesurande(string LeNom, int LIndex, string[] LesEntetes) { Nom = LeNom; Index = LIndex; Entetes = LesEntetes.ToList(); } public string Nom { get; private set; } public int Index { get; private set; } public List<string> Entetes { get; set; } } /// <summary> /// Correspond à une ligne de mesure /// </summary> public class DonneeTheolit { public DonneeTheolit(string LeNom, string LaDonneeRegex, List<Mesurande> LesMesurandes) { Nom = LeNom; DonneeRegex = LaDonneeRegex; Mesurandes = LesMesurandes; } public string Nom { get; private set; } public string DonneeRegex { get; private set; } public List<Mesurande> Mesurandes { get; private set; } public override string ToString() { return string.Format("{0}, {1} mesurandes", Nom, Mesurandes.Count); } } /// <summary> /// Classe qui gère le tout /// </summary> public class ImportDonneTheolit { private string filename; /// <summary> /// Construit une instance de DonneeTheolit à partir d'un csv /// </summary> /// <param name="Filename"></param> public ImportDonneTheolit(string Filename) { filename = Filename; if (!File.Exists(Filename)) throw new Exception("Fichier introuvable"); if (Path.GetExtension(Filename).ToLower() != ".csv") throw new Exception("Mauvaise extension"); //Lecture du fichier string[] lesLignes = File.ReadAllLines(Filename, Encoding.Default); //Hypothèse 1, les métadatas sont toujours dans les 10 premières lignes List<string[]> metadatas = (from l in lesLignes.Take(10) select l.Split(';') ).ToList(); //Hypothèse 2, le nom d'un mesurande est toujours précédé de varXXX // => on peut extraire l'index de début de chaque mesurande List<int> indexMesurandes = metadatas[0].Select((texte, ind) => new { texte, ind }).Where(x => Regex.IsMatch(x.texte, @"^var\d+$")).Select(x => x.ind + 1).ToList(); // Hypothèse 3, y'a pas de colonne vide entre 2 mesurandes // => on peut extraire les prototypes, sans s'embêter avec les _XX metadatas[9] = (from x in metadatas[9] let m = Regex.Match(x, @"_\d+$") select m.Success ? x.Replace(m.Value, "") : x ).ToArray(); int i, index1; List<PrototypeMesurande> prototypes = new List<PrototypeMesurande>(); for (i = 0; i < indexMesurandes.Count - 1; i++) { index1 = indexMesurandes[i]; int index2 = indexMesurandes[i + 1]; prototypes.Add(new PrototypeMesurande(metadatas[0][index1], index1, metadatas[9].Skip(index1).Take(index2 - index1).ToArray())); } //le dernier mesurande s'arrête à la fin de la ligne index1 = indexMesurandes[i]; prototypes.Add(new PrototypeMesurande(metadatas[0][index1], index1, metadatas[9].Skip(index1).ToArray())); //import des données Datas = (from l in lesLignes.Skip(10) let split = l.Split(';') select new DonneeTheolit(split[0], split[4], ToMesurandes(split, prototypes)) ).ToList(); } private List<Mesurande> ToMesurandes(string[] Split, List<PrototypeMesurande> Prototypes) { List<Mesurande> m = new List<Mesurande>(); foreach (PrototypeMesurande p in Prototypes) { m.Add(new Mesurande(p.Nom, (from e in p.Entetes let indexE = p.Entetes.IndexOf(e) let indexS = p.Index + indexE select new { Key = p.Entetes[indexE], Value = Convert.ToDouble(Split[indexS]) } ).ToDictionary(x => x.Key, x => x.Value) )); } return m; } public List<DonneeTheolit> Datas { get; private set; } /// <summary> /// Retourn eun mesurande selon la colonne DonneeRegex et son nom /// </summary> /// <param name="Nom"></param> /// <param name="DonneeRegex"></param> /// <returns></returns> public Mesurande TrouveMesurande(string Nom, string DonneeRegex) { return Datas.FirstOrDefault(d => d.DonneeRegex == DonneeRegex)?.Mesurandes.FirstOrDefault(m => m.Nom == Nom); } public override string ToString() { return string.Format("{0}, {1} lignes de mesures", filename, Datas.Count); } }
-
-
A la ligne où tu as l’erreur
-
D'accord, mais où dois-je ajouter ce public ?
Sachant que "Datas" est présent là:
public ImportDonneTheolit(string Filename) { Datas = (from l in lesLignes.Skip(10) let split = l.Split(';') select new DonneeTheolit(split[0], split[4], ToMesurandes(split, prototypes)) ).ToList(); }
et là :
public List<DonneeTheolit> Datas { get; private set; } -
Il faut que cette propriété soit public aussi
-
Bonjour
Suite à ton MP, je ne conçois le MP que s’il y a un besoin impérieux de discrétion.
Je te réponds donc ici.
Il faut que la classe soit public, pas seulement le constructeur.
Il faut probablement aussi que la classe Mesurande soit public.
Si c’est le cas, il faudra poster le code et peut-être aussi des captures d’écran.
-
Alors ton problème c'est que tu n'as pas compris ce qu'est un objet.
Et C# c'est un langage "tout" objet.
ÇaMesurande m = test.TrouveMesurande("Pression","Lower_Tol", "ALB-.M[12]...V.190");
c'est à la fois, inutile et "impossible".
Impossible puisque cet objet Mesurande encapsule toutes les valeurs de pression qui correspondent à ALB-.M[12]...V.190. On ne peut donc pas mettre cette valeurs (qui est un double) dans un Mesurande.
Et donc c'est inutile car m contient déjà cette valeur, il suffit de lui "prendre".
Le meilleur conseil que je puisse te donner c'est de trouver un cours ou un tuto sur l'objet avant d'aller plus loin dans te prochains.
J'en ai écrit un qui s'adresse aux autodidactes, c'est pas académique, mais c'est basé sur mes propres ratés.
https://codes-sources.commentcamarche.net/faq/11239-la-programmation-objet-appliquee-a-net-par-l-exemple-partie-1-sur-3
Mais y'en a pleins d'autres.
-
Bon j'aurais eu d'autres questions, mais j'ai émis des hypothèses (elles sont en commentaire dans le code).
Si elle ne sont pas exactes, faudra me le dire
Soit le CSV
Name:;test;;;;Modification;;var1;Température;;var2;Pression;var3;Hygrométrie;;;
Nr:;123;;;;Comments;;Nom Var;Temp;;nameVar2;;;;;;
Cout ;1234;;;;Control;;;;;;;;;;;
Modification date:;23/02/2021;;;;;;;;;;;;;;;
Resp of modif.:;moi;;;;;;Unit;deg C;;;;;;;;
File Name;test;;;;;;;;;;;;;;;
File Place;c:\Temp;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;
Name;Type;Yeux;Taille;Donnée_RegEx;donnée_test;blabla;bla;Nominal_Value_1;Lower_Tol_1;Upper_Tol_1;Nominal_Value_2;Lower_Tol_2;Nominal_Value_3;Lower_Tol_3;Upper_Tol_3;Autre_3
Pauline;Feminin;bleu;170;BLA-.P[12]...B.170;.;.;.;-5;-1;1;0;-60;1;2;3;4
Maxime;Masculin;vert;190;ALB-.M[12]...V.190;.;.;.;-0,5;-0,2;0,2;0;-19;1;2;3;4
Ce qui vu d'Excel donne
Voici d'abord 3 classes qui permettent de structurer les données/// <summary> /// Correspond à un relevé pour un mesurande /// </summary> class Mesurande { public Mesurande(string LeNom, Dictionary<string, double> LesDatas) { Nom = LeNom; Datas = LesDatas; } public string Nom { get; private set; } public Dictionary<string, double> Datas { get; private set; } public override string ToString() { return string.Format("{0}, {1} valeurs", Nom, Datas.Count); } } /// <summary> /// Permet de construire un mesurande à partir d'un fichier /// </summary> class PrototypeMesurande { public PrototypeMesurande(string LeNom, int LIndex, string[] LesEntetes) { Nom = LeNom; Index = LIndex; Entetes = LesEntetes.ToList(); } public string Nom { get; private set; } public int Index { get; private set; } public List<string> Entetes { get; set; } } /// <summary> /// Correspond à une ligne de mesure /// </summary> class DonneeTheolit { public DonneeTheolit(string LeNom, string LaDonneeRegex, List<Mesurande> LesMesurandes) { Nom = LeNom; DonneeRegex = LaDonneeRegex; Mesurandes = LesMesurandes; } public string Nom { get; private set; } public string DonneeRegex { get; private set; } public List<Mesurande> Mesurandes { get; private set; } public override string ToString() { return string.Format("{0}, {1} mesurandes", Nom, Mesurandes.Count); } }
Puis la classe qui lit le fichier et met ça en musique/// <summary> /// Classe qui gère le tout /// </summary> class ImportDonneTheolit { private string filename; /// <summary> /// Construit une instance de DonneeTheolit à partir d'un csv /// </summary> /// <param name="Filename"></param> public ImportDonneTheolit(string Filename) { filename = Filename; if (!File.Exists(Filename)) throw new Exception("Fichier introuvable"); if (Path.GetExtension(Filename).ToLower() != ".csv") throw new Exception("Mauvaise extension"); //Lecture du fichier string[] lesLignes = File.ReadAllLines(Filename, Encoding.Default); //Hypothèse 1, les métadatas sont toujours dans les 10 premières lignes List<string[]> metadatas = (from l in lesLignes.Take(10) select l.Split(';') ).ToList(); //Hypothèse 2, le nom d'un mesurande est toujours précédé de varXXX // => on peut extraire l'index de début de chaque mesurande List<int> indexMesurandes = metadatas[0].Select((texte, ind) => new { texte, ind }).Where(x => Regex.IsMatch(x.texte, @"^var\d+$")).Select(x => x.ind + 1).ToList(); //Hypothèse 3, y'a pas de colonne vide entre 2 mesurandes // => on peut extraire les prototypes, sans s'embêter avec les _XX metadatas[9] = (from x in metadatas[9] let m = Regex.Match(x, @"_\d+$") select m.Success ? x.Replace(m.Value, "") : x ).ToArray(); int i, index1; List<PrototypeMesurande> prototypes = new List<PrototypeMesurande>(); for (i = 0; i < indexMesurandes.Count - 1; i++) { index1 = indexMesurandes[i]; int index2 = indexMesurandes[i + 1]; prototypes.Add(new PrototypeMesurande(metadatas[0][index1], index1, metadatas[9].Skip(index1).Take(index2 - index1).ToArray())); } //le dernier mesurande s'arrête à la fin de la ligne index1 = indexMesurandes[i]; prototypes.Add(new PrototypeMesurande(metadatas[0][index1], index1, metadatas[9].Skip(index1).ToArray())); //import des données Datas = (from l in lesLignes.Skip(10) let split = l.Split(';') select new DonneeTheolit(split[0], split[4], ToMesurandes(split, prototypes)) ).ToList(); } private List<Mesurande> ToMesurandes(string[] Split, List<PrototypeMesurande> Prototypes) { List<Mesurande> m = new List<Mesurande>(); foreach (PrototypeMesurande p in Prototypes) { m.Add(new Mesurande(p.Nom, (from e in p.Entetes let indexE = p.Entetes.IndexOf(e) let indexS = p.Index + indexE select new { Key = p.Entetes[indexE], Value = Convert.ToDouble(Split[indexS]) } ).ToDictionary(x => x.Key, x => x.Value) )); } return m; } public List<DonneeTheolit> Datas { get; private set; } /// <summary> /// Retourn eun mesurande selon la colonne DonneeRegex et son nom /// </summary> /// <param name="Nom"></param> /// <param name="DonneeRegex"></param> /// <returns></returns> public Mesurande TrouveMesurande(string Nom, string DonneeRegex) { return Datas.FirstOrDefault(d => d.DonneeRegex == DonneeRegex)?.Mesurandes.FirstOrDefault(m => m.Nom == Nom); } public override string ToString() { return string.Format("{0}, {1} lignes de mesures", filename, Datas.Count); } }
Enfin le code qui utilise cette classeImportDonneTheolit test = new ImportDonneTheolit("TestTheolit.csv"); Mesurande m = test.TrouveMesurande("Pression", "ALB-.M[12]...V.190");
Ce qui donne


-
Ok, donc plus loin on pourrait imaginer une pression avec elle aussi plusieurs colonnes de données.
On va arrêter de parler de variable qui a plusieurs sens, dont un en développement, mais de mesurande (phénomène physique à mesurer) qui n’a qu’un sens qui correspond à ton tableau.
Les colonnes de données par mesurande sont elles toujours au nombre de 3?
-
Si ta capture m'avait permis de comprendre, je ne t'aurais pas demandé un fichier représentatif
Envoyer ta capture ne sert à rien.
Et je ne comprend toujours pas ce que vient faire Température là dedans, j'avais espéré comprendre avec un fichier représentatif
-
-
Je ne comprend pas, le lien Cjoint renvoi vers mon fichier représentatif (j'ai juste changé le nom des colonnes)
Température est le nom de la "variable" qui contient 3 données:
- Nominal_Value_X
-Lower_Tol_X
-Upper_Tol_X
Avec X l'indice (Exemple : "_1" )
Malheureusement je ne peux pas changer la structure du CSV..
-
- 1
- 2
Suivant

