Stringauswertung



  • 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?



  • Klar, du musst auch Platz in dem Array definieren.
    In read_number hast du das doch auch bei str_dbl so gemacht.
    Aber das sagt dir doch der Compiler. Evtl. mit Warnungen.

    Zudem ist gets böse, da es solange liest bis die Entertaste gedrückt wird.
    Egal wieviel Speicher da ist.
    Nimm fgets und stdin als Stream.



  • Auch wenn du diese Sachen ändern würdest: Du hast da noch Fehler! Und zwar entspricht das nicht deinen Beispielen... Nach dem Komma darf kein break erfolgen...



  • Danke!

    Ich habe jetzt versucht den Dezimaltrenner selbst zu definieren, aber mit dem code kommt immer 0 raus 😕

    Außerdem hat koschor recht. Nach dem ersten Dezimaltrenner soll die Zahl nicht ganz verworfen werden, sondern die Nachkommastellen ausgewertet werden. Es sei denn das Komms steht im Exponenten.

    Wie in Beispiel: -0,..0,1e-10,1."als -0,01·10^−10

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <string.h> 
    
    double read_number(char str[], char deztrenner){ 
    
        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] == deztrenner) 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[100];  
        char deztr;
    
        printf("Bitte Zahl eingeben:"); 
        fgets(str,100,stdin);
        printf("Bitte Dezimaltrenner eingeben:");
        scanf("%s",&deztr);
    
        printf ("dbl:     %.f\n",read_number(str,deztr)); 
    
        return 0; 
    }
    

    Wie kann ich das verbessern?



  • Ich weiß zwar nicht was für Werte du eingibst, aber

    - du brichst durch das break die Umwandlung ab. Da gehört ein continue hin

    - musst du auch den Tezimaltrenner ändern in '.', sonst bringt das nichts

    - bei der Ausgabe ist nur der . beim %f etwas blöd. Mach den mal weg.

    - %s bei scanf ist zum einlesen von Nullterminierten Zeichenketten gedacht.
    d.h. um ein Zeichen einzulesen brauchts du Platz für zwei. Dafür reicht deine Variable aber nicht.
    Such dir den Formatspecifier für Charakter.

    Lass dir zwischendurch mal die Werte ausgeben. Am Anfang von read_number und vor strtod.
    Dann kannst du sehen ob die Wandlung überhaupt erfolgreich war.
    Oder nimm den Debugger.



  • Danke Dirk!

    So ich hab das jetzt so modifiziert, wie du gesagt hast.

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <string.h> 
    
    double read_number(char str[], char deztrenner){ 
    
        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] == deztrenner) continue;
    
            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[100];  
        char deztr;
    
        printf("Bitte Zahl eingeben:"); 
        fgets(str,100,stdin);
        printf("Bitte Dezimaltrenner eingeben:");
        deztr=getchar();
    
        printf ("dbl:     %f\n",read_number(str,deztr)); 
    
        return 0; 
    }
    

    Das Problem ist jetzt aber, dass durch das continue der Dezimaltrenner nicht greift. Man muss die ganze Bedingung ändern oder?


Anmelden zum Antworten