Olivier Eckmann Posté(e) le 15 février 2018 Posté(e) le 15 février 2018 Bonjour, C'est pas propre à AutoCAD, mais j'ai un truc qui a l'air tout con, mais je ne m'en sort pas.Dans une datagridview, j'affiche des adresses avec le nom de la rue dans une colonne et le numéro de la rue dans une autre colonne.J'aimerais trié par ordre croissant mes adresses : Nom de rue puis n° croissant.Le problème c'est que j'ai des numéros stockés en texte car j'ai par exemple 1 2 5, mais aussi 3B 3C 3D 12B ...J'aimerais par exemple que 1B soit après 1 mais avant 2 et aussi que 10 soit après 9 et avant 11 et pas coincé entre 1 et 100 (tri alphabétique simple).Je pense que je vais être obligé de scinder tout ça en chiffre et lettre avant de trier, mais s'il y a une solution plus simple, je suis preneur. Merci, Olivier
lecrabe Posté(e) le 15 février 2018 Posté(e) le 15 février 2018 Hello Une idee "un peu debile" :- tu crees un nouveau champ/colonne (Copier/Coller) ...- Dans ce nouveau champ tu ajoutes 1 Million sur le debut numerique et apres ca devrait trier "normalement" !? Bye, lecrabe Autodesk Expert Elite Team
Olivier Eckmann Posté(e) le 15 février 2018 Auteur Posté(e) le 15 février 2018 Salut Pat, Pour la partie numérique pas de souci, mais il faut d'abord scindé la partie alpha, puis faire un tri sur les 3 colonnes, ce qui est moins évident, surtout avec la partie alpha qui peut être vide.Je pense avoir solutionner en créant une autre colonne qui concatène le nom de la rue puis _ puis la partie numérique du numéro sur 4 caractères puis _ puis la partie alpha ou rien si vide. par ex ça donne : RUE ALEXANDRE DUMAS_0012_B et ça je le trie comme du texte.Si je mets des espaces au lieu des underscore ça ne fonctionne pas.Olivier
(gile) Posté(e) le 15 février 2018 Posté(e) le 15 février 2018 Salut, pour le tri des numéros de rue, tu peux utiliser un comparateur du style : EDIT : code corrigé class StreetNumberComparer : IComparer<string> { public int Compare(string x, string y) { var regex = new Regex(@"(?i)^([0-9]+)([A-Z]*)$"); var matchX = regex.Match(x); if (!matchX.Success) throw new FormatException($"Numéro de rue non valide : {x}"); var matchY = regex.Match(y); if (!matchY.Success) throw new FormatException($"Numéro de rue non valide : {y}"); var compareNumber = int.Parse(matchX.Groups[1].Value).CompareTo(int.Parse(matchY.Groups[1].Value)); if (compareNumber == 0) return compareNumber = matchX.Groups[2].Value.ToUpper().CompareTo(matchY.Groups[2].Value.ToUpper()); else return compareNumber; } } Exemple :var numbers = new List<string> { "9", "10B", "243", "10a", "10" }; numbers.Sort(new StreetNumberComparer());numbers : "9", "10", "10a", "10B", "243" Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Olivier Eckmann Posté(e) le 15 février 2018 Auteur Posté(e) le 15 février 2018 Salut Gilles, Merci, c'est beaucoup plus concis que ce que j'avais trouvé. J'intègre ça dès demain. Olivier
(gile) Posté(e) le 15 février 2018 Posté(e) le 15 février 2018 J'ai corrigé une erreur dans le code. Suivant ce que tu as à faire, il peut être intéressant de définir une classe Adresse qui implémente IComparable avec des propriétés Rue (de type string) et Numero (d'un type StreetNumber qui implémente aussi IComparable comme ci-dessus). Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
(gile) Posté(e) le 16 février 2018 Posté(e) le 16 février 2018 Ça m'amusait et il m'est arrivé d'avoir à utiliser des adresses postales (dans un programme de distribution de fibre optique). Donc une petite classe qui définit un type Adresse (ici juste le numéro et le nom de la rue) et qui utilise un type NumeroDeRue (numéro avec éventuellement un suffixe numérique). Ces deux type sont "triables" (implémentation de IComparable et IComparable) Adresseusing System; using System.Text.RegularExpressions; namespace Gile.AdressePostale { /// <summary> /// Décit une adresse postale interne à une ville (numéro et nom de rue). /// </summary> public class Adresse : IComparable, IComparable<Adresse> { string street, text; NumeroDeRue number; /// <summary> /// Obtient le numéro. /// </summary> public NumeroDeRue Numero => number; /// <summary> /// Obtient le nom de la rue. /// </summary> public string Rue => street; /// <summary> /// Crée une nouvelle instance de Adresse. /// </summary> /// <param name="number">Numéro (avec éventuellement un suffixe alphabétique).</param> /// <param name="street">Nom de la rue.</param> public Adresse(string number, string street) { try { this.number = new NumeroDeRue(number); } catch { throw; } this.street = street ?? throw new ArgumentNullException("street"); text = number + " " + street; } /// <summary> /// Crée une nouvelle instance de Adresse. /// </summary> /// <param name="address">Adresse (numéro rue).</param> public Adresse(string address) { if (address == null) throw new ArgumentNullException("adress"); var regex = new Regex(@"(?i)^(?<number>\d+[A-Z]*)\s+(?<street>.+)$"); var match = regex.Match(address); if (!match.Success) throw new FormatException($"Format d'adresse non valide {address}"); text = address; number = new NumeroDeRue(match.Groups["number"].Value); street = match.Groups["street"].Value; } /// <summary> /// Compare l'instance actuelle avec un autre objet du même type et retourne un entier qui indique /// si l'instance actuelle précède ou suit un autre objet ou se trouve à la même position dans l'ordre de tri. /// </summary> /// <param name="obj">Objet à comparer à cette instance.</param> /// <returns>Valeur qui indique l'ordre relatif des objets comparés.</returns> public int CompareTo(object obj) { if (obj != null && !(obj is Adresse)) throw new ArgumentException("L'objet n'est pas de type Adresse"); return CompareTo((Adresse)obj); } /// <summary> /// Compare l'instance actuelle avec un autre objet du même type et retourne un entier qui indique /// si l'instance actuelle précède ou suit un autre objet ou se trouve à la même position dans l'ordre de tri. /// </summary> /// <param name="other">Instance de Adresse à comparer à cette instance.</param> /// <returns>Valeur qui indique l'ordre relatif des objets comparés.</returns> public int CompareTo(Adresse other) { if (other == null) return 1; int compareStreet = string.Compare(street, other.street, true); return compareStreet == 0 ? number.CompareTo(other.number) : compareStreet; } /// <summary> /// Détermine si l'objet spécifié est identique à l'objet actuel. /// </summary> /// <param name="obj">Objet à comparer à l'objet actuel.</param> /// <returns>true si l'objet spécifié est égal à l'objet actuel ; sinon, false.</returns> public override bool Equals(object obj) => obj is Adresse && text.ToUpper().Equals(((Adresse)obj).text.ToUpper()); /// <summary> /// Fait office de fonction de hachage par défaut. /// </summary> /// <returns>Code de hachage pour l'objet actuel.</returns> public override int GetHashCode() => text.ToUpper().GetHashCode(); /// <summary> /// Retourne une chaîne qui représente l'objet actuel. /// </summary> /// <returns>Chaîne qui représente l'objet actuel.</returns> public override string ToString() => text; } } NumeroDeRueusing System; using System.Text.RegularExpressions; namespace Gile.AdressePostale { /// <summary> /// Décrit un numéro de rue contenant éventuellement un suffixe alphabétique. /// </summary> public class NumeroDeRue : IComparable, IComparable<NumeroDeRue> { int number; string suffix, text; /// <summary> /// Obtient le numéro. /// </summary> public int Numero => number; /// <summary> /// Obtient le suffixe /// </summary> public string Suffixe => suffix; /// <summary> /// Crée une nouvelle instance de NumeroDeRue. /// </summary> /// <param name="streetNumber">Numéro complet.</param> public NumeroDeRue(string streetNumber) { text = streetNumber ?? throw new ArgumentNullException("streetNumber"); var regex = new Regex(@"(?i)^(\d+)([A-Z]*)$"); var match = regex.Match(text); if (!match.Success) throw new FormatException($"Format de numéro de rue non valide : {streetNumber}"); number = int.Parse(match.Groups[1].Value); suffix = match.Groups[2].Value; } /// <summary> /// Compare l'instance actuelle avec un autre objet du même type et retourne un entier qui indique /// si l'instance actuelle précède ou suit un autre objet ou se trouve à la même position dans l'ordre de tri. /// </summary> /// <param name="obj">Objet à comparer à cette instance.</param> /// <returns>Valeur qui indique l'ordre relatif des objets comparés.</returns> public int CompareTo(object obj) { if (obj != null && !(obj is NumeroDeRue)) throw new ArgumentException("L'objet n'est pas de type NumeroDeRue"); return CompareTo((NumeroDeRue)obj); } /// <summary> /// Compare l'instance actuelle avec un autre objet du même type et retourne un entier qui indique /// si l'instance actuelle précède ou suit un autre objet ou se trouve à la même position dans l'ordre de tri. /// </summary> /// <param name="other">Instance de NumeroDeRue à comparer à cette instance.</param> /// <returns>Valeur qui indique l'ordre relatif des objets comparés.</returns> public int CompareTo(NumeroDeRue other) { if (other == null) return 1; var compareNumber = number.CompareTo(other.number); return compareNumber == 0 ? string.Compare(suffix, other.suffix, true) : compareNumber; } /// <summary> /// Détermine si l'objet spécifié est identique à l'objet actuel. /// </summary> /// <param name="obj">Objet à comparer à l'objet actuel.</param> /// <returns>true si l'objet spécifié est égal à l'objet actuel ; sinon, false.</returns> public override bool Equals(object obj) => obj is NumeroDeRue && text.ToUpper().Equals(((NumeroDeRue)obj).text.ToUpper()); /// <summary> /// Fait office de fonction de hachage par défaut. /// </summary> /// <returns>Code de hachage pour l'objet actuel.</returns> public override int GetHashCode() => text.ToUpper().GetHashCode(); /// <summary> /// Retourne une chaîne qui représente l'objet actuel. /// </summary> /// <returns>Chaîne qui représente l'objet actuel.</returns> public override string ToString() => text; } } Un exemple d'utilisation :using Gile.AdressePostale; using System; using System.Linq; namespace ConsoleApp { class Program { static void Main(string[] args) { string[] adresses = new[] { "8 avenue John McCarthy", "5b rue du Code", "14 avenue John McCarthy", "5a rue du Code", "5 rue du Code", }; foreach (var item in adresses.OrderBy(a => new Adresse(a))) { Console.WriteLine(item); } Console.WriteLine(); foreach (var item in adresses.Select(a => new Adresse(a)).GroupBy(a => a.Rue)) { Console.WriteLine($"{item.Key} : {item.Count()} adresses"); } } } } Résultat :8 avenue John McCarthy 14 avenue John McCarthy 5 rue du Code 5a rue du Code 5b rue du Code avenue John McCarthy : 2 adresses rue du Code : 3 adresses Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
lecrabe Posté(e) le 16 février 2018 Posté(e) le 16 février 2018 Hello GillesLe Marseillais envisage de quitter le Soleil pour venir en Ile de France au fin fond de l'Essonne travailler avec Olivier !?Bon WE, Bye, lecrabe Autodesk Expert Elite Team
Olivier Eckmann Posté(e) le 16 février 2018 Auteur Posté(e) le 16 février 2018 Salut, Ayant été Marseillais durant 3 ans, je préfèrerais redescendre dans le sud. Je ne suis pas sûr que Gilles ait envie de monter voir les "parisiens", même si le sud Essonne est très sympa pour se balader et découvrir pas mal de petits bijoux (forestiers et architecturaux). Sinon, je n'ai malheureusement pas le niveau pour écrire ton code, mais je vais potasser ça pour essayer de tout comprendre avant de l'appliquer. Bon allez week-end oblige, je m'y remets demain! Olivier
(gile) Posté(e) le 16 février 2018 Posté(e) le 16 février 2018 Le Marseillais envisage de quitter le Soleil pour venir en Ile de France au fin fond de l'Essonne Même pas dans mes pires cauchemars !... Par contre, je travaillerais volontiers avec Olivier, depuis Marseille. ;) Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Olivier Eckmann Posté(e) le 16 février 2018 Auteur Posté(e) le 16 février 2018 Gilles, Ce serait un grand plaisir de travailler avec toi. Si l'occasion se présente, je n'hésiterais pas. Olivier
(gile) Posté(e) le 18 février 2018 Posté(e) le 18 février 2018 Une version commentée de la classe StreetNumberComparer. class StreetNumberComparer : IComparer<string> { public int Compare(string x, string y) { //var regex = new Regex(@"(?i)^([0-9]+)([A-Z]*)$"); var regex = new Regex(@" (?i) # ignorer la casse ^ # début de la chaîne ([0-9]+) # un ou plusieurs chiffres (groupe 1) ([A-Z]*) # zéro ou plusieurs lettres (groupe 2) $ # fin de la chaîne ", RegexOptions.IgnorePatternWhitespace); // option pour modèle avec des commentaires // évalue si la chaîne x correspond au modèle et constitue les groupes var matchX = regex.Match(x); if (!matchX.Success) throw new FormatException($"Numéro de rue non valide : {x}"); // évalue si la chaîne y correspond au modèle et constitue les groupes var matchY = regex.Match(y); if (!matchY.Success) throw new FormatException($"Numéro de rue non valide : {y}"); // compare les valeurs numériques des deux numéros (groupe 1) var compareNumber = int.Parse(matchX.Groups[1].Value).CompareTo(int.Parse(matchY.Groups[1].Value)); if (compareNumber == 0) // si les numéros sont égaux // compare les deux suffixes des numéros (groupe 2) return compareNumber = matchX.Groups[2].Value.ToUpper().CompareTo(matchY.Groups[2].Value.ToUpper()); else return compareNumber; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
didier Posté(e) le 18 février 2018 Posté(e) le 18 février 2018 Coucou Y'a besoin d'un programme pour ça ?Moi, quand j'arrive dans une rue, je me trompe pas, je regarde sur les maisons !!!C'est pourtant simple... Blague à part, je vois que (gile) excelle comme toujours, bien que je ne sache pas évaluer le programmeCe que je vois c'est que tu as la fibre "développeur", pour le moinsC'est là qu'on voit la force : expliquer un souci, le résoudreMoi il va falloir me l'expliquer plusieurs fois avant que je propose une solutionGrand respect ! Éternel débutant... Mon site perso : Programmer dans AutoCAD
(gile) Posté(e) le 18 février 2018 Posté(e) le 18 février 2018 Salut, Pourtant la problématique est simple : trier des chaînes de caractères figurant des numéros de rue ; soit des chaînes commençant par un ou plusieurs chiffres, éventuellement suivis de lettres.Par exemple "12", "5", "5B", "5A".On connait bien les problèmes posés par le tri alphabétique de chaînes figurant des nombres : "12" se retrouve avant "5". S'ajoute ici la question du suffixe. Il faut donc trouver une moyen de trier d'abord suivant la valeur numérique (nombre entier) la partie numérique au début de la chaîne, puis, en cas d'égalité de cette valeur, de trier de manière alphabétique le reste de la chaîne. Pour implémenter l'algorithme général ci-dessus, il faut trouver un moyen de séparer la partie numérique du début de la chaine du reste.On pourrait écrire une fonction, mais, malgré l'adage*, j'ai pensé qu'utiliser les expressions régulières était un moyen tout à fait adapté. Les expressions régulières constituent une technique aussi puissante qu'obscure pour traiter des chaînes de caractères. La classe .NET Regex utilise cette technique et permet à l'aide de modèles (patterns) de rechercher, modifier, récupérer des occurrences de chaînes dans une chaîne de caractère. Le "côté obscur" des expressions régulières, c'est la définition du modèle à l'aide des nombreux caractères spéciaux. Le modèle dans notre exemple est : @"(?i)^([0-9]+)([A-Z]*)$"(?i) indique qu'on veut ignorer la casse (on aurait aussi pu utiliser l'option RegexOptions.IgnoreCase^ indique que le caractère suivant doit se trouver en début de chaîne([0-9]+) les parenthèses indiquent un groupe constitué ici d'un ou plusieurs caractère numériques([A-Z]*) indique un autre groupe constitué de zéro ou plusieurs caractères alphabétiques (donc éventuellement une chaîne vide)$ indique que le caractère précédent doit se trouver en fin de chaîne Mais une fois le modèle élaboré, la méthode Regex.Match() permet à la fois de tester la validité du format de la chaîne (propriété Success) et, si le format est valide, de récupérer la partie numérique d'un côté et le suffixe de l'autre (propriété Groups) On peut ensuite comparer ces deux bouts de chaîne - soit dans l'implémentation de la méthode Compare() d'une classe implémentant IComparer qu'on poura utiliser comme argument avec List.Sort() ou avec IEnumerable.OrderBy() (CF réponse #4).- soit dans les méthodes CompareTo() d'une classe définissant un objet directement triable en implémentant IComaprable et IComparable (il est préférable d'implémenter les deux la méthode CompareTo() de IComparable appelant celle de IComaprable) (CF réponse #7). * à propos des expressions régulières, on entend parfois :"Certaines personnes, confrontées à un problème, pensent : "Je vais utiliser les expressions régulières". Maintenant, elles ont deux problèmes." Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
didier Posté(e) le 18 février 2018 Posté(e) le 18 février 2018 Coucou Merci de ces explications toutefois je suis largué... et je m 'interroge sur l'équipement dont tu es doté pour naviguer à cette altitude... Dans tous les cas un grand merci, il est bien possible qu'un jour on en ait besoin de ces explications. Par exemple : je pense que si j'avais dû traiter ce sujet je serais passé par une transformation en ascii pour ensuite gérer des numéros, mais c'est une vague idée, pour dire que chacun voit la résolution du problème avec ses outils et ses connaissances. Amicalement Éternel débutant... Mon site perso : Programmer dans AutoCAD
nG! Hebus Posté(e) le 19 février 2018 Posté(e) le 19 février 2018 Salut à tous, @Didier : je crois qu'il est pas sur cette planète, j'ai trouvé une carte mais c'est succins : http://stars.chromeexperiments.com/ "98% des soucis informatiques sont assis entre la chaise et le bureau !" "C'est parce que la vitesse de la lumière est supérieure à celle du son que tant de gens paraissent brillants avant d'avoir l'air con."
(gile) Posté(e) le 19 février 2018 Posté(e) le 19 février 2018 N'exagérons rien, tout ça s'apprend, en 2000 je n'avais pas d'ordi. Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Messages recommandés
Créer un compte ou se connecter pour commenter
Vous devez être membre afin de pouvoir déposer un commentaire
Créer un compte
Créez un compte sur notre communauté. C’est facile !
Créer un nouveau compteSe connecter
Vous avez déjà un compte ? Connectez-vous ici.
Connectez-vous maintenant