Calcul avec un String

laurrislaurris Membre
07:57 modifié dans API AppKit #1
Bonjour, j'ai une question qui a l'air bête et qui l'est peut-être.

Imaginons un string (NSString ou CString) qui dit @1+1.
Je voudrais obtenir le résultat (2 je crois :)) de type int.

Comment faire ?


Réponses

  • jaja Membre
    07:57 modifié #2
    Salut,
    regarde le projet "Busy Palette" dans les exemples d'IB ; il contient un formatteur qui fait ce que tu cherches.
  • AliGatorAliGator Membre, Modérateur
    07:57 modifié #3
    Tu cherches à  faire quoi au juste, à  prendre une chaine qui est une expression mathématique et à  calcluer son résultat ?
    Si c'est le cas j'ai peu qu'il faille un parseur de fonction mathématique (encore pour 1+1 ça va mais si tu demandes des expressions plus complexes avec des parenthèses, du cos et du sin, etc... en général c'est tout un projet)

    Il n'y a pas à  ma connaissance (mais je peux me trompoer, attention, faut p'tet chercher) de truc tout fait dans Cocoa pour prendre une chaà®ne et calculer son "résultat" mathématiquement parlant, pour le récupérer.
    Par contre tu peux passer par une NSTask et lancer l'utilitaire en ligne de commande "bc" qui fait très bien ça.
    Par exemple la commande "echo 1+1 | bc" va te retourner "2"
  • laurrislaurris Membre
    07:57 modifié #4
    Merci pour vos réponses. J'ai essayé la classe qui se trouve dans la IB palette de ja. Ca marche bien mais pour des opérations simples.
    Comme j'ai besoin de faire des choses plus compliquées, je vais soit utiliser le bc de Aligator dans une NSTask, soit une idée que je viens d'avoir: j'utiise dans mon projet le framework Webkit et ce framework a une méthode pour évaluer du javascript.
  • fouffouf Membre
    07:57 modifié #5
    Je te soupconne de ne pas avoir bien chercher dans les resources du site.
    http://www.objective-cocoa.org/index.php?p=ressource_detail&id=13.

    Alors, le code chez moi marche, mais il ya un pb de linking dans la version sur OC (résolu). Donc si tu veux essayer, je tiens juste à  te dire que mon truc est assez lent (surement plus que ce que t'as mis Aligator) mais qu'il marche bien.

    Si tu veux la bonne version, demande-moi, je vais pas enbeter hoksitan parce que j'ai fait une betise ;)
  • laurrislaurris Membre
    07:57 modifié #6
    T'as bien soupconné Fouf.
    Sinon, j'ai regardé dans les headers pour voir les différentes méthodes. J'ai l'impression que la classe qui m'intéresse est GMathFormatter;, or justement il n'y a pas de méthode définie dedans. Si c'est bien la classe qui m'intéresse et si tu as une version avec la doc, ça m'arrangerait bien que tu me l'envoie.
  • elfelf Membre
    07:57 modifié #7
    Je m'était déjà  posé la question; ai j'ai aussi eu bien du tracas!!!
    C'était aussi fouf qui avait la solution d'ailleur!

    http://www.objective-cocoa.org/forum/index.php?topic=1016.0
  • elfelf Membre
    07:57 modifié #8
    En Plus de détails:

    Télécharge le fichier lié et ajoute le à  ton projet (après l'avoir dézippé)!

    Ajoute les variables d'instances:

    &nbsp; &nbsp; NSTask&nbsp; &nbsp; &nbsp; &nbsp;  *evaluator;<br />&nbsp; &nbsp; NSPipe&nbsp; &nbsp; &nbsp; &nbsp;  *toPipe;<br />&nbsp; &nbsp; NSPipe&nbsp; &nbsp; &nbsp; &nbsp;  *fromPipe;<br />&nbsp; &nbsp; NSFileHandle&nbsp;  *toEvaluator;<br />&nbsp; &nbsp; NSFileHandle&nbsp;  *fromEvaluator;<br />
    


    Initialisation

    &nbsp; &nbsp; NSString *path = [ [NSBundle mainBundle]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pathForResource:@&quot;Evaluator&quot; ofType:@&quot;&quot;];<br /><br />&nbsp; &nbsp; toPipe&nbsp;  = [NSPipe pipe];<br />&nbsp; &nbsp; fromPipe = [NSPipe pipe];<br /><br />&nbsp; &nbsp; toEvaluator&nbsp;  = [toPipe fileHandleForWriting];<br />&nbsp; &nbsp; fromEvaluator = [fromPipe fileHandleForReading];<br /><br />&nbsp; &nbsp; evaluator = [ [NSTask alloc] init];<br />&nbsp; &nbsp; [evaluator setLaunchPath:path];<br /><br />&nbsp; &nbsp; [evaluator setStandardOutput:fromPipe];<br />&nbsp; &nbsp; [evaluator setStandardInput:toPipe];<br />&nbsp; &nbsp; [evaluator launch];<br /><br />&nbsp; &nbsp; [ [NSNotificationCenter defaultCenter]<br />&nbsp; &nbsp; &nbsp;  addObserver:self<br />&nbsp; &nbsp; &nbsp;  selector:@selector(gotData:)<br />&nbsp; &nbsp; &nbsp;  name:NSFileHandleReadCompletionNotification<br />&nbsp; &nbsp; &nbsp;  object:fromEvaluator];<br /><br />&nbsp; &nbsp; [fromEvaluator readInBackgroundAndNotify];<br />
    


    Pour donner l'opération (ou operation est la NSString qui contient ton opération):

    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [toEvaluator writeData:<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [operation dataUsingEncoding:NSASCIIStringEncoding<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; allowLossyConversion:YES] ];<br />
    


    Pour récupérer le résultat il faut implémenter cette méthode:

    - (void)gotData:(NSNotification *)not<br />{<br />&nbsp; &nbsp; NSData&nbsp; &nbsp; &nbsp; *data;<br />&nbsp; &nbsp; NSString&nbsp; &nbsp; *str;<br /><br />&nbsp; &nbsp; data = [ [not userInfo]<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; objectForKey:NSFileHandleNotificationDataItem];<br />&nbsp; &nbsp; str&nbsp; = [ [NSString alloc] initWithData:data<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; encoding:NSASCIIStringEncoding];<br /><br />&nbsp; &nbsp; //fait ce que tu veux avec le resultat, attention c&#39;est une NSString; si tu veux le convertire en int utilise le numberFormatter de Cocoa<br /><br />&nbsp; &nbsp; [fromEvaluator readInBackgroundAndNotify];<br />}<br />
    


    En gros, voilà  comment faire!

    [Fichier joint supprimé par l'administrateur]
  • AliGatorAliGator Membre, Modérateur
    07:57 modifié #9
    Heu elf, quitte à  passer par un NSTask pour lancer un utilitaire en ligne de commande, pourquoi prendre un utilitaire comme "Evaluator" (que je ne connais pas, j'ai pas de Mac sous la main là  pour télécharger et regarder mais bon) que tu auras à  mettre dans ton Bundle, au lieu d'utiliser directement "bc" fourni avec OSX ?
  • laurrislaurris Membre
    07:57 modifié #10
    BC marche pas mal. Je l'ai essayé inclus dans une NSTask. Pour ceux que ça intéresse, j'ai trouvé du code tout mâché ici: http://www.cocoadev.com/index.pl?BCWrapperSource

    Il manque quand même la possibilité d'avoir la partie entière d'un nombre décimal. Je croyais que ce genre d'opération de base y serait mais non.
  • ChachaChacha Membre
    07:57 modifié #11
    dans 1146065962:

    Il manque quand même la possibilité d'avoir la partie entière d'un nombre décimal. Je croyais que ce genre d'opération de base y serait mais non.

    En fait, si, ça y est en jouant sur la variable "scale".
    >scale=0
    >1.234/1
    1
    >1.678/1
    1

    ça donne la partie entière. Et pour arrondir, on rajoute simplement 0.5
    >(1.678+.5)/1
    2

    Mais pour les nombres négatifs, faut faire gaffe.

    +
    Chacha
  • elfelf Membre
    07:57 modifié #12
    tu peux faire des sinus, cosinus etc. avec ton bc? Tu lui fournis une simple NSString @sin(1+1) ???

    je ne connais pas :X
  • AliGatorAliGator Membre, Modérateur
    07:57 modifié #13
    Quand on ne connais pas, on tape "man bc" dans le terminal  :) :P
    MATH LIBRARY
          If bc is invoked with the -l option, a math library  is  preloaded  and
          the  default  scale  is  set to 20.  The math functions will calculate
          their results to the scale set at the time of  their  call.  The  math
          library defines the following functions:

          s (x)  The sine of x, x is in radians.

          c (x)  The cosine of x, x is in radians.

          a (x)  The arctangent of x, arctangent returns radians.

          l (x)  The natural logarithm of x.

          e (x)  The exponential function of raising e to the value x.

          j (n,x)
                  The bessel function of integer order n of x.
  • laurrislaurris Membre
    07:57 modifié #14
    Merci Chaha pour ton scale=0. Par contre, je n'arrive pas à  changer ce scale en cours de route. J'ai l'impression qu'on ne peut le définir qu'en début d'expression sans possibilité de le changer.
    Par exemple, si je veux la partie entière de 6/5 puis que je divise le résultat par 2, j'espère obtenir 0.5 et pas 0.
    J'ai essayé ça : "scale=0;a=6/5;scale=8;a/2" mais apparemment le scale reste bloqué à  0.
    J'ai peut-être mal lu la doc mais je ne vois pas comment faire.

  • AliGatorAliGator Membre, Modérateur
    07:57 modifié #15
    Salut laurris

    Tu peux te définir une fonction qui rendra la partie entière dans bc :
    define ent (x) {<br />&nbsp; auto r,s;<br />&nbsp; s = scale;<br />&nbsp; scale = 0;<br />&nbsp; r = x/1;<br />&nbsp; scale = s;<br />&nbsp; return r;<br />}
    
    Et ensuite faire des calculs avec :
    [tt]scale=10; ent(6/5)/2;[/tt]
Connectez-vous ou Inscrivez-vous pour répondre.