Search code examples
cstringbuffertoken

How to split String based on specific character without using strok


I was able to split the string buffer based on space without using strok function.

How can I also spilt the sring again based on = sign since i am concern about the values after the = sign .

So the logic is : split string into token based on space -->done then split each token based on = and avoid using strok--> issue here finally store only numric after sign into new buffer

int TokenizeString(char * s_String, char s_Token[][25], char c_Delimiter);

int main(void) {
    char buf[] = "abc=3000    Xyz=27.3   rb2act=11.82 ";

    //1.tokenizes each string without using strok
    char s_Token[15][25];
    memset(s_Token, 0, 200);

    int count = TokenizeString(buf, s_Token, ' ');
    int i;
    printf("Step 1 : Split the string  \n");

    for (i = 0; i <= count; i++) {
        printf("%s \n", s_Token[i]);
        // here is the issue , i need to store the result and spilt it again based on the = sign , i am concern about value after = sign
    }
    return EXIT_SUCCESS;
}

// Function to tokize the string without using strtok
int TokenizeString(char * s_String, char s_Token[][25], char c_Delimiter) {
    int j = 0;
    unsigned int i_Offset = 0;
    char b_Flag = 0;
    int count = 0;

    for (i_Offset = 0; i_Offset <= strlen(s_String); i_Offset++) {
        if (s_String[i_Offset] != c_Delimiter && s_String[i_Offset] != '\t' && s_String[i_Offset] != '\n' && s_String[i_Offset] != '\0') {
            s_Token[count][j] = s_String[i_Offset];
            j++;
            b_Flag = 1;
            continue;
        }

        if (b_Flag) {
            s_Token[count][j] = '\0';
            count++;
            j = 0;
            b_Flag = 0;
        }
    }
    return (count - 1);
}

Solution

  • The string can be split on spaces using strspn and strcspn and the tokens stored into dynamically allocated pointers.
    Not sure what was to be done with the two parts of each token, so this shows the token, the part that preceds the equal and a double that follows the equal. strcspn is used to find the equal in the token and strtod is used to parse the double. If the two parts need to be stored in memory, an array of structures might be worth looking into instead of pointers.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char **tokenize ( char *string, char delimiter);
    char **freetokens ( char **tokens);
    
    int main ( void) {
        char buf[] = "   abc=3000    Xyz=27.3   rb2act=11.82   ";
        char **tokens = NULL;
        char *last = NULL;
        size_t each = 0;
        size_t equal = 0;
        double value = 0.0;
    
        tokens = tokenize ( buf, ' ');
        if ( tokens) {
            each = 0;
            while ( tokens[each]) {
                if ( ( equal = strcspn ( tokens[each], "="))) {//look for the = ( except for = in index [0])
                    if ( equal < strlen ( tokens[each])) {//found an =
                        value = strtod ( tokens[each] + equal + 1, &last);//parse for a double
                        if ( last != tokens[each] + equal + 1 && *last == '\0') {//able to parse a double
                            printf ( "token\t %s\n", tokens[each]);//show the string
                            printf ( "up to =\t %.*s\n", equal, tokens[each]);//show the token up to the =
                            printf ( "double\t %f\n\n", value);//show the double
                        }
                        else {
                            printf ( "%s bad token\n\n", tokens[each]);
                        }
                    }
                    else {
                        printf ( "%s bad token\n\n", tokens[each]);
                    }
                }
                else {
                    printf ( "%s bad token\n\n", tokens[each]);
                }
                each++;
            }
    
            tokens = freetokens ( tokens);
        }
    
        return 0;
    }
    
    char **freetokens ( char **tokens) {
        size_t each = 0;
    
        if ( tokens) {
            while ( tokens[each]) {
                free ( tokens[each]);
                each++;
            }
            free ( tokens);
        }
    
        return NULL;
    }
    
    char **tokenize ( char *string, char delimiter) {
        char **lines = NULL;
        char **temp = NULL;
        char limit[2] = "";
        size_t skip = 0;
        size_t span = 0;
        size_t extent = 0;
        size_t line = 0;
        size_t len = strlen ( string);
    
        limit[0] = delimiter;
    
        if ( NULL == ( lines = malloc ( sizeof ( *lines) * 2))) {//allocate two pointers
            fprintf ( stderr, "malloc problem\n");
            return NULL;
        }
        lines[line + 1] = NULL;//sentinel
    
        while ( extent < len) {
            skip = strspn ( string + extent, limit);//get number of delimiters
            extent += skip;//advance past spaces
            if ( ( span = strcspn ( string + extent, limit))) {//find next delimiter or '\0'
                if ( NULL == ( lines[line] = malloc ( span + 1))) {
                    fprintf ( stderr, "malloc problem\n");
                    return lines;
                }
                strncpy ( lines[line], string + extent, span);
                lines[line][span] = '\0';
    
                if ( NULL == ( temp = realloc ( lines, sizeof ( *lines) * ( line + 3)))) {
                    fprintf ( stderr, "realloc problem\n");
                    return lines;
                }
                lines = temp;
                line++;
                lines[line] = NULL;
                lines[line + 1] = NULL;//sentinel
                extent += span;//advance past the token
            }
        }//loop to end of string
    
        return lines;
    }