-1

I'm parsing a string into variables and I almost have what I want.

The string to be parsed looks like this

char [128] = "D4 E 3 NullByte Sub";

Now I would like to split this into 4 variables:

  • D4 would be the location
  • E would be the direction
  • 3 would be the length
  • NullByte Sub is the name.

So far I've been using sscanf for splitting into variables using the code below (assume that the variables are already created):

sscanf(line, "%s %s %d %s", location, direction, &length, name);

So this scans location, direction and length correctly but chops off the Sub part of name.

I want to know how to ignore any other spaces and read what ever is left into name. No matter the number of spaces etc.

So if

line = "D4 E 3 NullByte Sub Ship Barrier"

Then I could expect the name to be

"NullByte Sub Ship Barrier"
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Argon
  • 55
  • 1
  • 7

3 Answers3

2

Like this:

int offset;
sscanf(line, "%s %s %d %n", location, direction, &length, &offset);
name = line + offset; // or strncpy or something, if you want a new string instead of just a pointer into the old one

%n records how many characters have been consumed so far. If you jump forward that many characters, then you get the rest of the string.

Side note: using %s without a maximum field width (or letting it allocate itself with the m modifier) is dangerous unless you're 100% sure that you'll never get an overly-long word.

2

The problem is that the %s format for scanf (and related function like sscanf) reads a space-delimited string.

Since there's no good "end of record" marker in the string (beyond the actual end of the string) it's hard to use sscanf at all, even with its special %[ format specifier.

Instead I suggest you learn about strtok and how to use it to "tokenize" a string.

With it you could do something like:

char *p = strtok(line, " ");
strcpy(location, p);

p = strtok(NULL, " ");
strcpy(direction, p);

p = strtok(NULL, " ");
length = strtol(p, NULL, 10);

strcpy(name, p + strlen(p) + 1);  // p + strlen(p) skips over the number, +1 to skip over the space as well
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

Why not simply use the sscanf character class format-specifier "%[^\n]" to read the name, e.g.

    if (sscanf (str, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
        printf ("loc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);

The field-width modifier must be used with any string conversion or sscanf is no better than gets(). The widths would correspond to the following declarations, e.g.

    char str[] = "D4 E 3 NullByte Sub", 
        loc[8], dir[8], name[64];
    int len;

A complete example would be:

#include <stdio.h>

int main (void) {

    char str[] = "D4 E 3 NullByte Sub", 
        str2[] = "D4 E 3 NullByte Sub Ship Barrier",
        loc[8], dir[8], name[64];
    int len;

    if (sscanf (str, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
        printf ("\nloc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);

    if (sscanf (str2, "%7s %7s %d %63[^\n]", loc, dir, &len, name))
        printf ("\nloc : %s\ndir : %s\nlen : %d\nname: %s\n", loc, dir, len, name);
}

Example Use/Output

$ ./bin/sscanf_loc-dir-name

loc : D4
dir : E
len : 3
name: NullByte Sub

loc : D4
dir : E
len : 3
name: NullByte Sub Ship Barrier
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • You're assuming that there will never be a newline in the name, but there's nothing in the question to back that assumption up. – Joseph Sible-Reinstate Monica Apr 10 '20 at 13:31
  • You are entirely correct -- that is an assumption I have made and it is entirely backed up by `char [128] = "D4 E 3 NullByte Sub";` and `line = "D4 E 3 NullByte Sub Ship Barrier"` - neither of which can contain an embedded `'\n'` as written. – David C. Rankin Apr 10 '20 at 21:20