IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Comment utiliser un ensemble d'intervalles passé en argument ?


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Research Scientist
    Inscrit en
    Mars 2004
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Research Scientist
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 40
    Par défaut Comment utiliser un ensemble d'intervalles passé en argument ?
    Bonjour,

    Je me retrouve avec un double problème sans trouver de façon "simpliste" et efficace pour le résoudre.

    Programme actuel:
    J'ai un programme qui en fonction de la valeur (float), entrée en argument, va faire appel à une fonction définie.
    Mon programme est tel que pour les valeurs comprises:
    - entre [0 et 20[: On appelle la fonction A
    - entre [20 et 50[: On appelle la fonction B
    - entre [50 et infinie[: On appelle la fonction C
    Ces intervalles sont codés en dur dans mon fichier

    Pour le moment rien de bien compliqué.

    Maintenant, je voudrais definir ces intervalles et les passer en argument de mon programme de telle sorte que ces intervalles puissent être définis par l'utilisateur.
    Ainsi l'utilisateur pourrait écrire:
    ./prog -definition 1:0-30,2:30-60,1:60-70,3:70-+ 'liste de valeur'

    Mon premier soucis est le suivant:
    j'arrive à recupérer sans soucis la chaine (string) "1:0-30,2:30-60,1:60-70,3:70-+"
    Mais je ne trouve pas de moyen simple de la parser.
    Je veux dire par là que je n'arrive pas à prendre direct les nombres, je dois faire un check caractère par caractère récupérer le debut de la chaine et la fin et la convertir en suite en int. C'est très lourd.
    Voulant être le plus optimal, quelqu'un aurait il des astuces pour le faire ?

    Mon second soucis est le suivant:
    Comment arriver à faire des intervalles propres?
    Sachant que les fonctions peuvent être définies à plusieurs endroits, je n'arrive pas à écrire un truc simple qui puisse prendre cet ensemble d'intervalle défini par l'utilisateur, de sorte à avoir un truc comme ça (en se basant sur l'exemple précédent):
    Utilise l'algo:
    - A si la valeur est entre [0 et 30[ ou [60,70[
    - B si la valeur est entre [30 et 60 [
    - C pour le reste.
    Si quelqu'un a une idée de structure, ou des astuces/algo pour coder ça en C proprement, je suis preneur aussi.

    Merci d'avance.

  2. #2
    Membre expérimenté Avatar de quetzacoatl
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    168
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 168
    Par défaut
    En fait voulez-vous changer souvent ces valeurs ou voulez vous juste que ce soit une possibilité?
    Car sinon vous pouvez faire un fichier texte ou seront stockees toutes ces valeurs(vous pouvez éventuellement faire un autre programme dédié à cela ou l'intégrer dans votre programme).
    Sinon vous pouvez convertir les chaines en int avec la fonction atoi() et en float avec la fonction atof() il me semble.

  3. #3
    Membre confirmé
    Homme Profil pro
    Research Scientist
    Inscrit en
    Mars 2004
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Research Scientist
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 40
    Par défaut
    En faite, les valeurs par défaut sont très bonnes mais en fonction de la puissance/type du Pc ces intervalles sont différents. Il faudrait que l'utilisateur puisse faire varier ces intervalles.
    De plus, cela permet aussi de tester l’efficacité de chaque fonction.
    Car sans avoir a recompiler, on pourrait utiliser la fonctions A sur de 0 a 100, puis tester l'algo B et ainsi de suite...
    Utiliser uniquement atoi() permet de convertir les string en int en effet, mais ne permet pas de faire le découpage de la chaine "1:0-30,2:30-60,1:60-70,3:70-+"
    Pour le moment, apres un :, je lis caractère par caractère jusqu’à ce que je rencontre un -. Puis j'utilise atoi() pour la chaîne de caractère située entre ces 2 séparateur pour avoir le nombre. Je n'aime pas cette solution, mais je ne sais ps si il y en a d'autre en C. (Je code bcp en python avec des expressions régulières, ce cas la est très très simple alors).

    Apres que ces intervalles soit en paramètre ou dans un fichier, cela m'est égale. Je cherche juste un moyen "élégant" pour résoudre ça.

  4. #4
    Membre émérite
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Par défaut
    Pour le parsing tu peux utiliser strtok_r() ou regex(). Allez pour le fun:
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <regex.h>
     
    int parse(const char *args)
    {
    	char *dup, *p, *save_p;
    	regex_t preg;
    #	define NMATCH (3+1)
    	regmatch_t match[NMATCH];
    	const char *regexp = "([0-9]+):([0-9]+)-([0-9]+|\\+)";
    	if (!(dup = strdup(args))) {
    		fprintf(stderr, "failed to duplicate `%s'\n", args);
    		return 1;
    	}
    	if (regcomp(&preg, regexp, REG_EXTENDED)) {
    		fprintf(stderr, "failed to compile regexp `%s'\n", regexp);
    		free(dup);
    		return 2;
    	}
    	for (p = strtok_r(dup, ",", &save_p); p; p = strtok_r(NULL, ",", &save_p)) {
    		int number;
    		int begin;
    		int end;
    		int end_infinity = 0;
    		if (regexec(&preg, p, NMATCH, match, 0)) {
    			fprintf(stderr, "failed to match on `%s'\n", p);
    			regfree(&preg);
    			free(dup);
    			return 2;
    		}
    		/* given () start at 1 */
    		number = atoi(p+match[1].rm_so);
    		begin = atoi(p+match[2].rm_so);
    		if (p[match[2].rm_so] == '+')
    			end_infinity = 1;
    		else
    			end = atoi(p+match[3].rm_so);
    		printf("Found %d %d %d (in %s)\n", number, begin, end, p);
    	}
    	free(dup);
    	regfree(&preg);
    	return 0;
    }
     
    int main(void)
    {
    	const char *args = "1:0-30,2:30-60,1:60-70,3:70-+";
    	parse(args);
    	return 0;
    }
    Mais tu pourrais laisser le split avec ',' être fait par getopt (et donc avoir en ligne de commande plusieurs fois le paramètre: genre -s 1:0-30 -s 2:30-60 -s 1:60-70 -s 3:70-+). Et le parsing d'un intervalle pourrait être basique, genre strchr(':'), du coup du peut récupérer l'identifiant de fonction, strchr('-'), recupérer alors le début, etc. (voire même, si tu n'as qu'un nombre limité de fonction, laisser ça à getopt: -1 0-30 -2 30-60 -1 60-70 -3 70-+)

    Après une petite structure genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     struct space {
        int fnum;
        int begin;
        int end;
        int end_is_infinity;
    }
    Peut aider, mais l'algo de recherche, je pense que t'es obligé de te taper une boucle sur ton tableau d'intervalles et de prendre le premier qui correspond (quitte à trier ton tableau pour tomber d'abord là où tu va le plus souvent tomber, et aussi vérifier qu'il n'y a pas d'intersections).

  5. #5
    Membre confirmé
    Homme Profil pro
    Research Scientist
    Inscrit en
    Mars 2004
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Research Scientist
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 40
    Par défaut
    Merci D[r]eadLock , cette solution est très élégante, je n'en demandais pas tant
    Je ne savais pas que l'on pouvait utiliser des expressions régulières en C, merci bcp.

  6. #6
    Membre émérite
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Par défaut
    Citation Envoyé par shidosh Voir le message
    Merci D[r]eadLock , cette solution est très élégante, je n'en demandais pas tant
    En fait, après avoir tapé strtok et regex, je me suis demandé si je savais encore les utiliser , et en 10 minutes, la réponse était là. C'est un peu lourd à mon goût quand même... Quant l'autre motivation, c'est simple, un post sans faute d'orthographe (à priori), bien expliqué, sans code mal indenté (bon à vrai dire sans code du tout), ça change et est un petit défi en soit

    Citation Envoyé par shidosh
    Je ne savais pas que l'on pouvait utiliser des expressions régulières en C
    Attention, ce ne sont que les expressions rationnelles POSIX (man 7 regex), pas celles auxquelles on est souvent habitué, pcre (Perl Compatible Regular Expression), et suis tombé dans le panneau (d'où les 10 minutes ), j'avais mis \d+ et non [0-9]+


    PS: pour rendre la chose plus élégante on peut changer le for en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for (p = NULL; p = strtok_r(p?dup:NULL, ",", &save_p); /* nop */) {
    PS2: tag/bouton résolu

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par D[r]eadLock Voir le message
    PS: pour rendre la chose plus élégante on peut changer le for en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for (p = NULL; p = strtok_r(p?dup:NULL, ",", &save_p); /* nop */) {
    Plus élégante... ou non...

    ça fait un peu de l'obsfuscation ...

  8. #8
    Membre émérite
    Avatar de D[r]eadLock
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    504
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 504
    Par défaut
    Citation Envoyé par souviron34 Voir le message
    Plus élégante... ou non...

    ça fait un peu de l'obsfuscation ...
    C'est sûr, d'ailleurs je me suis planté c'est l'inverse, i.e. p = strtok_r(p?NULL:dup...).
    Mais l'avantage, c'est que le séparateur (",") n'est définit qu'une seule fois, de même pour le save_ptr, ça évite du code redondant.

Discussions similaires

  1. [XL-2007] Comment utiliser TextBox pour déterminer deux intervales
    Par chikitin dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 05/07/2010, 15h18
  2. Réponses: 3
    Dernier message: 21/01/2009, 09h35
  3. Comment executer une liste de méthodes passées en argument
    Par Mengué georges dans le forum Langage
    Réponses: 11
    Dernier message: 01/10/2007, 17h33
  4. Réponses: 1
    Dernier message: 22/03/2007, 20h08
  5. [SQL] Comment utiliser dans une requête une variable passée par URL
    Par foffa dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 31/08/2006, 12h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo