wonderer
wonderer

Reputation: 3557

Parsing a string with tokens for the first and last words (in C)

I'm going to try to explain the problem.

I am getting a string containing a registry key. For example:

HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey

now, I need to parse that string into 3 different char (or char *) variables. After the parsing it'll be something like:

string1 = HKEY_CURRENT_USER
string2 = \Software\MyProgram\SomeOtherValue\   /* with the '\' */
string3 = SomeKey

Not only do I need to group the backslashes; I also don't know how many of them are there. I could have something like:

HKEY_CURRENT_USER\Software\SomeKey

or something like:

HKEY_CURRENT_USER\Software\SomeValue\SomeOthervalue\Someblah\SomeKey

I tried with strtok() and strcspn() but i'm getting very confused here... Any idea how to get this done? Code is appreciated.

Thanks!

Upvotes: 1

Views: 1270

Answers (4)

akappa
akappa

Reputation: 10490

Copy the string into an allocated one and split the variable placing a '\0' in the slash where you want to truncate it.

You can "scan" the string for slashes using the strchr function.

void to_split(char *original, int first_slash, int second_slash, char **first, char **second, char **third) {
        int i;
        char *first_null;
        char *second_null;
        char *allocated;

        if (first_slash >= second_slash)
                return;
        allocated = malloc(strlen(original) + 1);
        *first = allocated;
        strcpy(allocated, original);
        for (i = 0, first_null = allocated; i < first_slash && (first_null = strchr(first_null,'\\')); i++);

        if (first_null) {
                *first_null = '\0';
                *second = first_null + 1;
        }

        second_null = allocated + strlen(original);
        i = 0;
        while (i < second_slash && second_null > allocated)
            i += *second_null-- == '\\';

        if (++second_null > allocated) {
            *second_null = '\0';
            *third = second_null + 1;
        }
}

Usage:

int main (int argc, char **argv) {
        char *toSplit = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
        char *first;
        char *second;
        char *third;
        to_split(toSplit, 1, 3, &first, &second, &third);
        printf("%s %s %s\n", first, second, third);
        return 0;
}

It isn't the best code in the world, but it gives you an idea.

Upvotes: 2

Nick Lewis
Nick Lewis

Reputation: 4230

strchr(char*, char) : locate first occurrence of char in string

strrchr(char*, char) : locate last occurrence of char in string

char* str = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char token1[SIZE], token2[SIZE], token3[SIZE];

char* first = strchr(str, '\\');
char* last = strrchr(str, '\\')+1;

strncpy(token1, str, first-str);
token1[first-str] = '\0';
strncpy(token2, first, last-first);
token2[last-first] = '\0';
strcpy(token3, last);

We use strchr to find the first '\', and strrchr to find the last '\'. We then copy to token1, token2, token3 based on those positions.

I decided to just use fixed size buffers instead of calloc-ing, because that's not so important to illustrate the point. And I kept messing it up. :)

Upvotes: 2

abelenky
abelenky

Reputation: 64682

Pseudo-Code:

Step 1: Scan forward until the first "\", note the index.

Step 2: Scan Backward from the end to the last "\" (the first "\" encountered when going backwards), note the index.

Step 3: StrCpy the relevant pieces out into 3 strings.

Code: (does not rely on strrchr, or other methods you seem to have issues with)

void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key);

int main(void)
{
    char* regKey = "HKEY_CURRENT_USER\\Software\\MyProgram\\SomeOtherValue\\SomeKey";
    char* TopLevel;
    char* Path;
    char* Key;

    ParseRegEntry(regKey, &TopLevel, &Path, &Key);

    printf("1: %s\n2: %s\n3: %s\n", TopLevel, Path, Key);
    free(TopLevel);
    free(Path);
    free(Key);

    return 0;
}

void ParseRegEntry(char* regKey, char** TopLevel, char** Path, char** Key)
{
    int firstDelimiter = 0;
    int lastDelimiter = strlen(regKey)-1;
    int keyLen;

    while(regKey[firstDelimiter] != '\\')
    {
        firstDelimiter++;
    }

    while(regKey[lastDelimiter] != '\\')
    {
        lastDelimiter--;
    }
    keyLen = strlen(regKey) - lastDelimiter-1;

    *TopLevel = (char*)malloc(firstDelimiter+1);
    strncpy(*TopLevel, regKey, firstDelimiter);
    (*TopLevel)[firstDelimiter] = '\0';

    *Path = (char*)malloc(lastDelimiter - firstDelimiter+2);
    strncpy(*Path, regKey+firstDelimiter, lastDelimiter - firstDelimiter);
    (*Path)[lastDelimiter-firstDelimiter] = '\0';


    *Key = (char*)malloc(keyLen+1);
    strncpy(*Key, regKey+lastDelimiter+1, keyLen);
    (*Key)[keyLen] = '\0';
}

Upvotes: 2

Twotymz
Twotymz

Reputation: 412

Here's an example using strchr and strrchr to scan forwards and backwards in the string for the '\'.

char str[] = "HKEY_CURRENT_USER\Software\MyProgram\SomeOtherValue\SomeKey";
char *p, *start;
char root[128], path[128], key[128];

p = strchr (str, '\\');
strncpy (root, str, p - str);
start = p;
p = strrchr (str, '\\') + 1;
strncpy (path, start, p - start);
strcpy (key, p);

Upvotes: 1

Related Questions