Stringauswertung



  • Nabend!

    Ich möchte eine Funktion "double read_number(char eingabe[], char deztrenner)" schreiben, die folgendes ausführen kann:

    Die eingegebenen Strings sollen ausgewertet werden und falls möglich Dezimalzahlen ausgegeben werden. Die Dezimalzahlen werden nur bis zum ersten Komma erkannt. Die Zahlen, die nach dem Komma folgen, verfallen. Außerdem verfallen auch alle anderen Zeichen die keine Zahl bilden. E bzw. e wird als Literal für den Exponenten erkannt.

    Hier ein paar Beispiele:

    "-0,000.100.2" als -0,0001002

    "€5.000.000,00" als 5000000

    "1000aaa aaa0a, 0,0,0,0,0" als 10000,

    "-0,..0,1e-10,1."als -0,01·10^−10,

    "1-2--3-4/5+6\7,,,...1E0-2$" als 1 234 567·10^2, usw.

    Es sei noch erwähnt, dass ich als Programmierneuling bezeichnet werden kann.

    Vielleicht könnt ihr mir ja ein paar Tipps geben, wie ich an so eine Aufgabe rangehen kann und in welchen Bereichen ich mich einlesen sollte 🙂





  • CJosef schrieb:

    Hi
    http://www.cplusplus.com/reference/cstdlib/strtod/

    Danke.

    Mehr brauche ich nicht?



  • Sicher, ein bisschen mehr brauchst du schon.
    Du fragst nach einem Tipp und den hast du jetzt.
    Was fehlt dir noch?



  • Mit dem Code kann man ja schonmal ein wenig die einzelnen Teile des strings differenzieren

    #include <stdio.h> 
    #include <stdlib.h>
    
    int main( void )
    {
        char const * str = "-1234.5678 47.11E+2 Hallo";
        double value1, value2;
        char * succ;
    
        value1 = strtod( str, &succ );
        value2 = strtod( succ, &succ );
    
        printf( "Wert des Strings \"%s\": 1 => %f   2 => %f\nEs folgt: \'%s'\n", str, value1, value2, succ );
    
        return 0;
    }
    

    Ausgabe:
    Wert des Strings "-1234.5678 47.11E+2 Hallo": 1 => -1234.567800 2 => 4711.000000
    Es folgt: ' Hallo'

    Wie schafft man es, dass das Programm Buchstaben bzw. Sonderzeichen innerhalb der Zahl verwirft? Wenn ich z.b in die Zahl einen Buchstaben einfüge, verwirft das Programm die Zahlen bis zum Buchstaben.



  • Du musst deinen String vorbehandeln indem du ungültige Zeichen rausschmeisst.

    Zeichenweise durch den Text gehen und jedes Zeichen überprüfen.



  • DirkB schrieb:

    Du musst deinen String vorbehandeln indem du ungültige Zeichen rausschmeisst.

    Zeichenweise durch den Text gehen und jedes Zeichen überprüfen.

    Vielen Dank bis hierhin!

    Um die Zeichenkette durchzugehen brauche ich wahrscheinlich eine for-schleife. Und wie schmeiße ich dann die ungültigen Zeichen raus?



  • MarvC schrieb:

    Um die Zeichenkette durchzugehen brauche ich wahrscheinlich eine for-schleife. Und wie schmeiße ich dann die ungültigen Zeichen raus?

    Du brauchst einen Leseindex und einen Schreibindex. Wenn das Zeichen gültig ist erhöst du beide.
    Wenn das Zeichen ungültig ist, erhöst du nur den Leseindex.

    Bei deinem Beispiel mit dem Stringliteral brauchst du noch ein Array in dem du Speichern kannst.

    char const * str = "-1234.5678 47.11E+2 Hallo";
        char valid[100];
        double value1, value2;
    
        int r,w
        for(r=0,w=0;str[r]!='\0';++r)
        { if (istgültig(str[r]) ) // Was immer auch für dich passt
            valid[w++] = str[r];
        }
        valid[w] = '0';
    


  • MarvC schrieb:

    Und wie schmeiße ich dann die ungültigen Zeichen raus?

    Indem Du z.B. nur die gültigen Zeichen in einen anderen String kopierst:

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int main( void )
    {
        char str[] = "-12abcd34.5678E+0x2 Hallo";
        char str_dbl[80];
        size_t i,j;
        char minus;
        double dbl;
    
        for (minus = 1, i = j = 0; i < strlen(str); ++i)
        {
            if (str[i] == ',') break;
            if (
                (str[i] == '-' && minus)
                || (str[i] >= '0' && str[i] <= '9')
                || (str[i] == 'e' || str[i] == 'E')
                )
            {
                str_dbl[j++] = str[i];
                minus = 0;
            }
        }
        str_dbl[j] = '\0';      /* Abschlussnull nicht vergessen! */
    
        printf ("str:     %s\n",str);
        printf ("str_dbl: %s\n",str_dbl);
        dbl = strtod (str_dbl,NULL);
        printf ("dbl:     %.f\n",dbl);
    
        return 0;
    }
    

    viele grüße
    ralph



  • Für den Test auf Ziffern gibt es isdigit aus ctype.h
    Dort gibt es auch toupper. Dann brauchst du nur mit Großbuchstaben vergleichen.

    Die anderen Funktionen wie isalpha sind auch interessant für dich.



  • rkhb schrieb:

    ...
        for (minus = 1, i = j = 0; i < strlen(str); ++i)
    ...
    

    strlen in der for Schleife finde ich aber nicht so schön.
    Dafür würde ich lieber eine außerhalb der Schleife berechnete Variable einsetzen.

    size_t slen = strlen (str);
    for (minus = 1, i = j = 0; i < slen; ++i)
    

    Vielleicht würde der Compiler deine Version optimieren, vielleicht aber auch nicht,
    und dann würde in jedem Schleifendurchlauf der komplette String zwecks Berechnung der Länge durchlaufen werden.



  • Das strlen ist doch gar nicht nötig, da man ja sowieso alle Elemente des Strings "anfasst". Da kann man auch gleich auf die '\0' testen.



  • Jepp. 👍



  • Pah, Schleife, sowas Langweiliges! Also wenns um Obfuskation geht, habe ich Folgendes beizusteuern:

    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
    
    void validate (char*a,char*b)
    {
        static char m,e,p;
        if(*a==','||*a==0){*b=0;return;}
        else if(*a=='-'&&!m){*b++=*a;m=~m;}
        else if(((*a|96)=='e')&&!e){*b++=*a;e=~e;m=~m;}
        else if(*a=='.'&&!p){*b++=*a;p=~p;}
        else if(isdigit(*a))*b++=*a;
        validate(++a,b);
    }
    
    int main( void )
    {
        char str[] = "-12abcd3-4.56:78e+0e1e0,234 Hallo";
        double dbl;
        printf ("str:     %s\n",str);
        validate (str,str);
        printf ("str:     %s\n",str);
        dbl = strtod (str, NULL);
        printf ("dbl:     %.f\n",dbl);
        return 0;
    }
    

    :xmas1:

    viele grüße
    ralph



  • Besten Dank für die Hilfe!

    Ich habe das ganze versucht als Funktion zu schreiben.

    double number(char str[]){
    
        char str_dbl[80];
        size_t i,j; 
        char minus; 
        double dbl; 
    
        for (minus = 1, i = j = 0; i < strlen(str); ++i) 
        { 
            if (str[i] == ',') break; 
            if ( 
                (str[i] == '-' && minus) 
                || (str[i] >= '0' && str[i] <= '9') 
                || (str[i] == 'e' || str[i] == 'E') 
                ) 
            { 
                str_dbl[j++] = str[i]; 
                minus = 0; 
            } 
        } 
        str_dbl[j] = '\0';       
    
        return str_dbl;
    
    }
    

    Das Problem ist, dass der return-wert nicht zurückgegeben wird. Woran kann das liegen?



  • MarvC schrieb:

    Besten Dank für die Hilfe!

    Ich habe das ganze versucht als Funktion zu schreiben.

    double number(char str[]){ //Funktion soll double-Wert zurückgeben
       
        char str_dbl[80];
        size_t i,j; 
        char minus; 
        double dbl; // die Variable wird deklariert, aber nicht weiter verwendet
        
        for (minus = 1, i = j = 0; i < strlen(str); ++i) 
        { 
            if (str[i] == ',') break; 
            if ( 
                (str[i] == '-' && minus) 
                || (str[i] >= '0' && str[i] <= '9') 
                || (str[i] == 'e' || str[i] == 'E') 
                ) 
            { 
                str_dbl[j++] = str[i]; 
                minus = 0; 
            } 
        } 
        str_dbl[j] = '\0';       
        
        return str_dbl; // gibt Zeiger auf char-array zurück, das nach Beenden der Funktion nicht mehr existiert
        
    
        
    }
    

    Das Problem ist, dass der return-wert nicht zurückgegeben wird. Woran kann das liegen?



  • Möchtest du nicht lieber dbl zurückgeben?

    Du definierst die Funktion mit dem Rückgabetyp double, gibst aber ein Array of char zurück.

    Lokale Arrays kann man aber nicht zurückgeben, da sie nach dem Ende der Funktion nicht mehr gültig sind.



  • Achso ok 😃

    double read_number(char str[]){
    
        char str_dbl[80];
        size_t i,j; 
        char minus; 
        double dbl;
    
        for (minus = 1, i = j = 0; i < strlen(str); ++i) 
        { 
            if (str[i] == ',') break; 
            if ( 
                (str[i] == '-' && minus) 
                || (str[i] >= '0' && str[i] <= '9') 
                || (str[i] == 'e' || str[i] == 'E') 
                ) 
            { 
                str_dbl[j++] = str[i]; 
                minus = 0; 
            } 
        } 
        str_dbl[j] = '\0';      /* Abschlussnull nicht vergessen! */ 
    
        dbl = strtod (str_dbl,NULL);
    
        return dbl;
    
    }
    

    So funktioniert das jetzt 🙂



  • Ändere die Abbruchbedingung der for-Schleife noch in str[i] != '\0' oder ganz kurz str[i] .
    Der Grund steht weiter oben.

    Du musst allerdings auch noch mehr Sonderfälle abfangen.
    Ein Vorzeichen kann auch '+' sein.

    In der Mitte von einer Zahl hat ein Vorzeichen nichts zu suchen.
    Es sei denn es gehört zum Exponenten.



  • Ich würde das Programm jetzt gerne so erweitern, dass ich selbst den string eingebe.

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <string.h> 
    
    double read_number(char str[]){
    
        char str_dbl[80];
        size_t i,j; 
        char minus; 
        double dbl;
    
        for (minus = 1, i = j = 0; i < strlen(str); ++i) 
        { 
            if (str[i] == ',') break; 
            if ( 
                (str[i] == '-' && minus) 
                || (str[i] >= '0' && str[i] <= '9') 
                || (str[i] == 'e' || str[i] == 'E') 
                ) 
            { 
                str_dbl[j++] = str[i]; 
                minus = 0; 
            } 
        } 
        str_dbl[j] = '\0';       
    
        dbl = strtod (str_dbl,NULL);
    
        return dbl;
    
    }
    
    int main( void ) 
    { 
        char str[]; /*<- Möglicher Fehler?*/
    
        printf("String:");
        gets(str);
    
        printf ("dbl:     %.f\n",read_number(str)); 
    
        return 0; 
    }
    

    Ich habe versucht das mit gets() umzusetzen, aber das funktioniert nicht. Liegt wahrscheinlich an char str[].

    Muss ich mir ne andere Alternative überlegen?


Anmelden zum Antworten