2

if for instance i have a string: Hi:my:name:is:lacrosse1991: how could I use strtok to retrieve just the is (in other words the fourth field)? This would be similar to how you would use cut in bash, where i would just do cut -d ":" -f 4. If this is the wrong function to be doing such a thing, please let me know, any help is much appreciated, thanks! (I've just recently started teaching myself C, I apologize ahead of time if these are obvious questions that i am asking)

here is an example of the cut command that I would use

x=$(echo "$death" | cut -d ':' -f 4)
y=$(echo "$death" | cut -d ':' -f 5)
z=$(echo "$death" | cut -d ':' -f 6)
dsolimano
  • 8,870
  • 3
  • 48
  • 63
lacrosse1991
  • 2,972
  • 7
  • 38
  • 47

3 Answers3

6

If you know it's the 4th field you just call strtok() 4 times - there is no way of jumping to the 4th field without scanning the entire string ( which is what strtok is doing)

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
1

One way to extract the Nth field (whilst keeping the string in original condition after the call) is to use the following getFld function. First, the requisite headers:

#include <stdio.h>
#include <string.h>
#include <malloc.h>

Now the function itself, which I hope is documented well enough:

char *getFld (char *srchStr, char delim, int numFld) {
    char *copyStr, *retStr, *tmpStrPtr, delims[2];

    // Make a copy so as to not damage original.

    if ((copyStr = strdup (srchStr)) == NULL) return NULL;

    // Create delimiter string from character.

    delims[0] = delim; delims[1] = '\0';
    retStr = NULL;

    // Start loop, extracting fields.

    tmpStrPtr = strtok (copyStr, delims);
    while (tmpStrPtr != NULL) {
        // If this is the field we want, make a copy.

        if (numFld == 0) retStr = strdup (tmpStrPtr);

        // Get next field.

        tmpStrPtr = strtok (NULL, delims);
        numFld--;
    }

    // Clean up, return field copy (must be freed eventually) or NULL.

    free (copyStr);
    return retStr;
}

And, finally, a test program for it:

int main (void) {
    int i = 0;
    char str[] = "Hi:my:name:is:lacrosse1991";
    char *fld;
    while ((fld = getFld (str, ':', i)) != NULL) {
        printf ("Field %d is '%s'\n", i, fld);
        free (fld);
        i++;
    }
    return 0;
}

Upon compiling and running this, I get:

Field 0 is 'Hi'
Field 1 is 'my'
Field 2 is 'name'
Field 3 is 'is'
Field 4 is 'lacrosse1991'

Now, keep in mind that strdup is not standard C but, if your implementation doesn't have it, you can use this one. You may also want to change the behaviour on strdup failure since the current case cannot be distinguished from an out of range field.

But, this code should be fine as a baseline to start with.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

I'd avoid strtok for this purpose (and most others, for that matter). Under the circumstances, I think I'd just use sscanf with a scanset conversion:

char field_four[128];   
sscanf(input_string, "%*[^:]:%*[^:]:%*[^:]:%127[^:]:", field_four);

In this, we start by repeating %*[^:]: three times. Each of these reads a string including any characters except a colon, then a colon. The * means that should be read from the input, but ignored (not assigned to anything). Then, for the fourth field we have the same thing, except we do not include the *, so that field does get assigned, in this case to field_four (though you should obviously use a more meaningful name).

For the fourth field, I've also added a specification of the maximum length. Since sscanf always includes a \0 to terminate the string, but doesn't include it in the count, we need to specify a size one smaller than the size of the buffer.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111