7 Stimmen

C: Leere Token aus einer Zeichenkette mit strtok zerlegen

Meine Anwendung erzeugt Zeichenketten wie die folgende. Ich muss die Werte zwischen dem Trennzeichen in einzelne Werte zerlegen.

2342|2sd45|dswer|2342||5523|||3654|Pswt

Ich verwende strtok um dies in einer Schleife zu tun. Für das fünfte Token erhalte ich 5523. Ich muss jedoch den leeren Wert zwischen den beiden Trennzeichen berücksichtigen || auch. 5523 sollte der sechste Token sein, so wie ich es verlange.

token = (char *)strtok(strAccInfo, "|");

for (iLoop=1;iLoop<=106;iLoop++) { 
            token = (char *)strtok(NULL, "|");
}

Irgendwelche Vorschläge?

2 Stimmen

Strtok() ist wohl das Schlimmste, was der C-Standard zu bieten hat. Sie könnten Ihren eigenen Parser schreiben.

1voto

Jerry Coffin Punkte 452852

Verwenden Sie etwas anderes als strtok . Es ist einfach nicht dafür gedacht, das zu tun, wonach Sie fragen. Wenn ich das gebraucht habe, habe ich normalerweise strcspn o strpbrk und habe den Rest des Tokeninzings selbst erledigt. Wenn es Ihnen nichts ausmacht, die Eingabezeichenfolge zu ändern wie strtok sollte es ziemlich einfach sein. Zumindest auf Anhieb scheint es so, als ob es funktionieren sollte:

// Warning: untested code. Should really use something with a less-ugly interface.
char *tokenize(char *input, char const *delim) { 
    static char *current;    // just as ugly as strtok!
    char *pos, *ret;
    if (input != NULL)
        current = input;

    if (current == NULL)
        return current;

    ret = current;
    pos = strpbrk(current, delim);
    if (pos == NULL) 
        current = NULL;
    else {
        *pos = '\0';
        current = pos+1;
    }
    return ret;
}

0 Stimmen

Da der Auftraggeber nur nach einem Begrenzungszeichen sucht, strchr() könnte stattdessen verwendet werden strpbrk() .

0 Stimmen

Ich habe es ein wenig anders gemacht. Trotzdem danke.

1voto

Accountant م Punkte 5859

Inspiriert durch Antwort von Patrick Schlüter Ich habe diese Funktion erstellt, sie soll thread-sicher sein, leere Token unterstützen und die ursprüngliche Zeichenkette nicht verändern

char* strTok(char** newString, char* delimiter)
{
    char* string = *newString;
    char* delimiterFound = (char*) 0;
    int tokLenght = 0;
    char* tok = (char*) 0;

    if(!string) return (char*) 0;

    delimiterFound = strstr(string, delimiter);

    if(delimiterFound){
        tokLenght = delimiterFound-string;
    }else{
        tokLenght = strlen(string);
    }

    tok = malloc(tokLenght + 1);
    memcpy(tok, string, tokLenght);
    tok[tokLenght] = '\0';

    *newString = delimiterFound ? delimiterFound + strlen(delimiter) : (char*)0;

    return tok;
}

können Sie es verwenden wie

char* input = "1,2,3,,5,";
char** inputP = &input;
char* tok;
while( (tok=strTok(inputP, ",")) ){
    printf("%s\n", tok);
}

Dies soll die Ausgabe

1
2
3

5

Ich habe es für einfache Strings getestet, aber noch nicht in der Produktion verwendet, und es auf Codeüberprüfung auch, damit Sie sehen können, was andere darüber denken

1 Stimmen

Wenn Sie auf einem Posix-Rechner arbeiten, können Sie die Zeile 'tok = malloc(tokLenght + 1); memcpy(tok, string, tokLenght); tok[tokLenght] = ' \0 ';'` einfach durch tok = strndup(string, tokLength);

0voto

Bash Punkte 75

Nachstehend finden Sie die Lösung, die bei mir jetzt funktioniert. Vielen Dank an alle, die geantwortet haben.

Ich verwende LoadRunner. Daher einige ungewohnte Befehle, aber ich glaube, der Ablauf ist leicht genug zu verstehen.

char strAccInfo[1024], *p2;
int iLoop;

Action() {  //This value would come from the wrsp call in the actual script.
    lr_save_string("323|90||95|95|null|80|50|105|100|45","test_Param");

    //Store the parameter into a string - saves memory. 
    strcpy(strAccInfo,lr_eval_string("{test_Param}"));
    //Get the first instance of the separator "|" in the string
    p2 = (char *) strchr(strAccInfo,'|');

    //Start a loop - Set the max loop value to more than max expected.
    for (iLoop = 1;iLoop<200;iLoop++) { 

        //Save parameter names in sequence.
        lr_param_sprintf("Param_Name","Parameter_%d",iLoop);

        //Get the first instance of the separator "|" in the string (within the loop).
        p2 = (char *) strchr(strAccInfo,'|');           

        //Save the value for the parameters in sequence. 
        lr_save_var(strAccInfo,p2 - strAccInfo,0,lr_eval_string("{Param_Name}"));   

        //Save string after the first instance of p2, as strAccInfo - for looping.
        strcpy(strAccInfo,p2+1);

        //Start conditional loop for checking for last value in the string.
        if (strchr(strAccInfo,'|')==NULL) {
            lr_param_sprintf("Param_Name","Parameter_%d",iLoop+1);
            lr_save_string(strAccInfo,lr_eval_string("{Param_Name}"));
            iLoop = 200;    
        }
    }
}

0 Stimmen

Irgendwann müssen Sie erklären, warum Sie globale Variablen anstelle von lokalen Variablen haben und warum Sie keinen Rückgabetyp für die Funktion haben (das ist sehr altmodisches C). Oder, besser noch, korrigieren Sie den Code so, dass er auch unter strengen Compilerwarnungen sauber kompiliert werden kann. Die Verwendung von iLoop = 200; zu erreichen break; zerbrechlich ist. Es ist nicht klar, warum der Wert 200 überhaupt in der Schleifensteuerung verwendet wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X