Разобрать строку в C89 / C90 - PullRequest
       29

Разобрать строку в C89 / C90

0 голосов
/ 10 апреля 2020

Я разбираю строку в переменных и у меня почти есть то, что я хочу.

Строка, которую нужно проанализировать, выглядит следующим образом

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

Теперь я хотел бы разделить это на 4 переменные:

  • D4 будет местоположение
  • E будет направление
  • 3 будет длина
  • NullByte Sub - это имя.

До сих пор я использовал sscanf для разбиения на переменные с помощью приведенного ниже кода (предположим, что переменные уже созданы):

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

Так что это сканирует местоположение, направление и длину правильно, но отсекает часть Sub имени.

Я хочу знать, как игнорировать любые другие пробелы и читать то, что когда-либо осталось в имени. Неважно, сколько пробелов и т. Д. c.

Так что если

line = "D4 E 3 NullByte Sub Ship Barrier"

Тогда я мог бы ожидать, что имя будет

"NullByte Sub Ship Barrier"

Ответы [ 3 ]

2 голосов
/ 10 апреля 2020

Проблема в том, что формат %s для scanf (и связанной с ним функции, такой как sscanf) читает строку с разделителем *1007*.

Поскольку в строке нет хорошего маркера «конца записи» (за пределами фактического конца строки), трудно вообще использовать sscanf, даже с его специальным спецификатором формата %[.

Вместо этого я Предлагаем вам узнать о strtok и о том, как использовать его для «токенизации» строки.

С ее помощью вы можете сделать что-то вроде:

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
2 голосов
/ 10 апреля 2020

Примерно так:

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 записывает, сколько символов было использовано до сих пор. Если вы перепрыгнете на столько символов вперед, то получите остальную часть строки.

Примечание: использование %s без максимальной ширины поля (или разрешение выделять себя с модификатором m) опасно если вы не уверены на 100%, что никогда не получите слишком длинное слово.

0 голосов
/ 10 апреля 2020

Почему бы просто не использовать sscanf класс символов спецификатор формата "%[^\n]" для чтения имени, например,

    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);

ширина поля модификатор должен использоваться с любым преобразованием строк, или sscanf не лучше, чем gets(). Ширина будет соответствовать следующим объявлениям, например

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

Полный пример будет:

#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);
}

Пример использования / Вывод

$ ./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
...