Je réponds tardivement à ce post, alors je ne sais pas si c'est encore pertinent, mais au cas où cela puisse servir à quelqu'un je vais quand même poser ma proposition.
Je me disais en l'occurrence qu'il pouvait s'agir d'un cas d'usage pour la library Sprache, qui sert à créer dans parsers. Une des points intéressants est l'aspect déclaratif du code servant à définir ces parsers et qui le rend facile à lire.
N'ayant pas les détails des règles appliquées pour les données, je me suis permis d'extrapoler. Voici les données que j'ai utilisées en référence :
Code txt : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 03/04/2023 Désérialisation un grand classique 243 Rue de LAMBREYAGE 59450 Sin-le-Noble Liste des Artistes Art Contemporain Emplacement Nom Age Pays Goodies Expos Sell 1 Matthieu dethé 45 France 23 18 6 2 Benoit Breton 34 France 12 5 2 3 Jean Flou 65 Belgique 53 4 2 Nombre 3 Street Art Emplacement Nom Age Pays Expos 1 Sabart Deco 32 France 140 2 Laurent Pez 23 Suisse 4 Nombre 2 Art Grotesque Emplacement Nom Age Pays Goodies Expos Sell 1 Grouchy Deco 32 France 9999 71 4 2 Masset Pez 23 Suisse 4 7 6 Nombre 2 Nombre Total d'exposants 7
Les classes de modèle de données C# (exposition, en-tête et pied de fichier, catégories, artistes) :
La classe de grammaire servant à définir les parsers :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 namespace Expositions { public class Exhibition { public Exhibition(Headers headers, IEnumerable<Category> categories, Footer footer) { Headers = headers; Categories = categories.ToArray(); Footer = footer; _artists = new Lazy<Artist[]>(() => Categories.SelectMany(c => c.Artists).ToArray()); } public Headers Headers { get; } public IEnumerable<Category> Categories { get; } public Footer Footer { get; } public IEnumerable<Artist> Artists => _artists.Value; private Lazy<Artist[]> _artists; } public class Headers { public Headers(DateTime date, string title, int number, string street, string zipCode, string city) { Date = date; Title = title; Number = number; Street = street; ZipCode = zipCode; City = city; } public DateTime Date { get; } public string Title { get; } public int Number { get; } public string Street { get; } public string ZipCode { get; } public string City { get; } } public class Category { public Category(string title, IEnumerable<Artist> artists, int count) { Name = title; Artists = artists.ToArray(); Count = count; } public string Name { get; } public IEnumerable<Artist> Artists { get; } public int Count { get; } } public class Artist { public int Slot { get; internal set; } public string Name { get; internal set; } = ""; public int Age { get; internal set; } public string Country { get; internal set; } = ""; public int Goodies { get; internal set; } public int Exhibits { get; internal set; } public int Sell { get; internal set; } } public class Footer { public Footer(int count) { Count = count; } public int Count { get; internal set; } } }
Un programme console tout simple pour utiliser le parser :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 using Sprache; namespace Expositions { public static class Grammar { #region Primitives public static readonly Parser<string> Date = Parse.Digit.Or(Parse.Char('/')).Except(Parse.LineEnd).AtLeastOnce().Text().Token(); public static readonly Parser<string> SimpleText = Parse.AnyChar.Except(Parse.LineEnd).Many().Text().Token(); public static readonly Parser<string> Integer = Parse.Digit.AtLeastOnce().Text().Token(); public static readonly Parser<string> ZipCode = Parse.LetterOrDigit.Except(Parse.LineEnd).Many().Text().Token(); public static Parser<string> Label(string lookup) => from label in Parse.String(lookup).Text().Token() select label; #endregion #region Headers public static readonly Parser<Headers> Headers = from date in Date from title in SimpleText from number in Integer from street in SimpleText from zipCode in ZipCode from city in SimpleText select new Headers ( DateTime.Parse(date), title, int.Parse(number), street, zipCode, city ); #endregion #region Artists public static Parser<Artist> Artist(CategoryParseOptions options) { var return0 = Parse.Preview(Parse.AnyChar).Except(Parse.String("Nombre")).Return("0"); var returnEmpty = Parse.Preview(Parse.AnyChar).Except(Parse.String("Nombre")).Return(""); var parseSlot = options.Slot ? (from slot in Integer select slot) : Parse.Return("0"); var parseName = options.Name ? (from name in SimpleText select name) : Parse.Return(""); var parseAge = options.Age ? (from age in Integer select age) : Parse.Return("0"); var parseCountry = options.Country ? (from country in SimpleText select country) : Parse.Return(""); var parseGoodies = options.Goodies ? (from goodies in Integer select goodies) : Parse.Return("0"); var parseExhibits = options.Exhibits ? (from exhibits in Integer select exhibits) : Parse.Return("0"); var parseSell = options.Sell ? (from sell in Integer select sell) : Parse.Return("0"); return from slot in parseSlot from name in parseName from age in parseAge from country in parseCountry from goodies in parseGoodies from exhibits in parseExhibits from sell in parseSell select new Artist { Slot = int.Parse(slot), Name = name, Age = int.Parse(age), Country = country, Goodies = int.Parse(goodies), Exhibits = int.Parse(exhibits), Sell = int.Parse(sell), }; } public class CategoryParseOptions { public bool Slot { get; set; } public bool Name { get; set; } public bool Age { get; set; } public bool Country { get; set; } public bool Goodies { get; set; } public bool Exhibits { get; set; } public bool Sell { get; set; } } public static readonly Parser<Category> Category = from title in SimpleText from slot in Parse.Optional(Label("Emplacement")) from name in Parse.Optional(Label("Nom")) from age in Parse.Optional(Label("Age")) from country in Parse.Optional(Label("Pays")) from goodies in Parse.Optional(Label("Goodies")) from exhibits in Parse.Optional(Label("Expos")) from sell in Parse.Optional(Label("Sell")) let options = new CategoryParseOptions { Slot = slot.GetOrDefault() != null, Name = name.GetOrDefault() != null, Age = age.GetOrDefault() != null, Country = country.GetOrDefault() != null, Goodies = goodies.GetOrDefault() != null, Exhibits = exhibits.GetOrDefault() != null, Sell = sell.GetOrDefault() != null } from artists in Artist(options).Except(Parse.String("Nombre")).Many() from label in Parse.String("Nombre").Token() from count in Integer select new Category(title, artists, int.Parse(count)); public static readonly Parser<IEnumerable<Category>> Categories = from label in Parse.String("Liste des Artistes").Token() from categories in Category.Many() select categories; #endregion #region Footer public static readonly Parser<Footer> Footer = from label in Parse.String("Nombre Total d'exposants").Token() from count in Integer select new Footer(int.Parse(count)); #endregion #region Exhibition public static readonly Parser<Exhibition> Exhibition = from headers in Headers from label in Parse.String("Liste des Artistes").Token() from categories in Category.Many() from footer in Footer select new Exhibition(headers, categories, footer); #endregion } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 using Expositions; using Sprache; Console.WriteLine("Start"); var source = await File.ReadAllTextAsync("source.txt"); var exhibition = Grammar.Exhibition.Parse(source); var headers = exhibition.Headers; Console.WriteLine($"Date : {headers.Date}"); Console.WriteLine($"Titre : {headers.Title}"); Console.WriteLine($"Nombre : {headers.Number}"); Console.WriteLine($"Rue : {headers.Street}"); Console.WriteLine($"Code postal : {headers.ZipCode}"); Console.WriteLine($"Ville : {headers.City}"); foreach (var category in exhibition.Categories) { Console.WriteLine(); Console.WriteLine(category.Name); foreach (var artist in category.Artists) { Console.WriteLine(artist.Country); } } Console.WriteLine(); Console.WriteLine($"Count: {exhibition.Footer.Count}"); Console.WriteLine("End");
Partager