Tokenizing strings in C

Ik heb geprobeerd een tekenreeks te tokeniseren met SPACE als scheidingsteken, maar het werkt niet. Heeft iemand een suggestie waarom het niet werkt?

Bewerken: tokeniseren met:

strtok(string, " ");

De code is als volgt

pch = strtok (str," ");
while (pch != NULL)
{
  printf ("%s\n",pch);
  pch = strtok (NULL, " ");
}

Antwoord 1, autoriteit 100%

Doe het als volgt:

char s[256];
strcpy(s, "one two three");
char* token = strtok(s, " ");
while (token) {
    printf("token: %s\n", token);
    token = strtok(NULL, " ");
}

Opmerking: strtokwijzigt de tokenisering van de tekenreeks, dus het kan geen const char*zijn.


Antwoord 2, autoriteit 84%

Hier is een voorbeeld van het gebruik van strtok. Houd er rekening mee dat strtokde invoertekenreeks vernietigt (en daarom ooitgebruikt op een stringconstante

char *p = strtok(str, " ");
while(p != NULL) {
    printf("%s\n", p);
    p = strtok(NULL, " ");
}

Eigenlijk is het belangrijk om op te merken dat het doorgeven van een NULLals eerste parameter aan strtokaangeeft dat het het volgende token moet ophalen van de string die het eerder aan het tokenen was.

p>


Antwoord 3, autoriteit 16%

strtok kan erg gevaarlijk zijn. Het is niet draadveilig. Het beoogde gebruik is om keer op keer in een lus te worden aangeroepen, waarbij de uitvoer van de vorige oproep wordt doorgegeven. De strtok-functie heeft een interne variabele die de status van de strtok-aanroep opslaat. Deze status is niet uniek voor elke thread – deze is globaal. Als een andere code strtok gebruikt in een andere thread, krijg je problemen. Ook niet het soort problemen dat je wilt opsporen!

Ik raad je aan te zoeken naar een regex-implementatie of sscanf te gebruiken om de string uit elkaar te halen.

Probeer dit:

char strprint[256];
char text[256];
strcpy(text, "My string to test");
while ( sscanf( text, "%s %s", strprint, text) > 0 ) {
   printf("token: %s\n", strprint);
}

Opmerking: de tekenreeks ‘tekst’ wordt vernietigd als deze wordt gescheiden. Dit is misschien niet het gewenste gedrag =)


Antwoord 4, autoriteit 4%

Je kunt de code vereenvoudigen door een extra variabele in te voeren.

#include <string.h>
#include <stdio.h>
int main()
{
    char str[100], *s = str, *t = NULL;
    strcpy(str, "a space delimited string");
    while ((t = strtok(s, " ")) != NULL) {
        s = NULL;
        printf(":%s:\n", t);
    }
    return 0;
}

Antwoord 5, autoriteit 4%

Ik heb een aantal tekenreeksfuncties gemaakt om waarden te splitsen, door minder pointers te gebruiken, omdat deze code bedoeld is om op PIC18F-processors te draaien. Die processors kunnen niet echt goed omgaan met pointers als je weinig vrije RAM beschikbaar hebt:

#include <stdio.h>
#include <string.h>
char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A";
int findchar(char *string, int Start, char C) {
    while((string[Start] != 0)) { Start++; if(string[Start] == C) return Start; }
    return -1;
}
int findcharn(char *string, int Times, char C) {
   int i = 0, pos = 0, fnd = 0;
    while(i < Times) {
       fnd = findchar(string, pos, C);
        if(fnd < 0) return -1;
        if(fnd > 0) pos = fnd;
       i++;
   }
   return fnd;
}
void mid(char *in, char *out, int start, int end) {
    int i = 0;
    int size = end - start;
    for(i = 0; i < size; i++){
        out[i] = in[start + i + 1];
    }
    out[size] = 0;
}
void getvalue(char *out, int index) {
    mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1));
}
void main() {
   char n_pwd[7];
   char n_d1[7];
   getvalue(n_d1, 1);
   printf("Value: %s\n", n_d1);
} 

Antwoord 6

Bij het lezen van de strtok-documentatie zie ik dat je een NULL-pointer moet invoeren na de eerste “initialisatie”-aanroep. Misschien heb je dat niet gedaan. Gewoon een gok natuurlijk.


Antwoord 7

Hier is nog een strtok()-implementatie, die de mogelijkheid heeft om opeenvolgende scheidingstekens te herkennen (de strtok()van de standaardbibliotheek heeft dit niet)

De functie maakt deel uit van de BSD-gelicentieerde stringbibliotheek, genaamd zString. Je bent meer dan welkom om bij te dragen 🙂

https://github.com/fnoyanisi/zString

char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */
    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;
    if (str == 0)
        str = static_str;
    /* get length of string */
    while(str[strlength])
        strlength++;
    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }
    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }
    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }
    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';
    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;
        return str;
}

Zoals vermeld in eerdere berichten, omdat strtok(), of degene die ik hierboven heb geïmplementeerd, vertrouwt op een static *char-variabele om de locatie van het laatste scheidingsteken tussen opeenvolgende oproepen, moet u extra voorzichtig zijn bij het omgaan met multi-threaded applicaties.


Antwoord 8

int not_in_delimiter(char c, char *delim){
    while(*delim != '\0'){
            if(c == *delim) return 0;
            delim++;
    }
    return 1;
}
char *token_separater(char *source, char *delimiter, char **last){
char *begin, *next_token;
char *sbegin;
/*Get the start of the token */
if(source)
  begin = source;
else
  begin = *last;
sbegin = begin;
/*Scan through the string till we find character in delimiter. */
while(*begin != '\0' && not_in_delimiter(*begin, delimiter)){
       begin++;
}
/* Check if we have reached at of the string */
if(*begin == '\0') {
/* We dont need to come further, hence return NULL*/
   *last = NULL;
    return sbegin;
}
/* Scan the string till we find a character which is not in delimiter */
 next_token  = begin;
 while(next_token != '\0' && !not_in_delimiter(*next_token, delimiter))    {
    next_token++;
 }
 /* If we have not reached at the end of the string */
 if(*next_token != '\0'){
  *last = next_token--;
  *next_token = '\0';
   return sbegin;
}
}
 void main(){
    char string[10] = "abcb_dccc";
    char delim[10] = "_";
    char *token = NULL;
    char *last = "" ;
    token  = token_separater(string, delim, &last);
    printf("%s\n", token);
    while(last){
            token  = token_separater(NULL, delim, &last);
            printf("%s\n", token);
    }

}

Je kunt een gedetailleerde analyse lezen op blog vermeld in mijn profiel 🙂

LEAVE A REPLY

Please enter your comment!
Please enter your name here

2 − 1 =

Other episodes