Как определить длину строки sscanf'd? - PullRequest
2 голосов
/ 09 декабря 2010

Я анализирую строку, которая соответствует предсказуемому шаблону:

  1. 1 символ
  2. целое число (одна или несколько цифр)
  3. 1 двоеточие
  4. строка, длина которой пришла от # 2

Например:

s5:stuff

Я легко вижу, как разобрать это с помощью PCRE или тому подобного, но я предпочел бы придерживаться простых операций с цепочками ради скорости.

Я знаю, что мне нужно сделать это в 2 шага, потому что я не могу выделить строку назначения, пока не узнаю ее длину. Моя проблема заключается в изящном получении смещения для начала указанной строки. Какой-то код:

unsigned start = 0;
char type = serialized[start++]; // get the type tag
int len = 0;
char* dest = NULL;
char format[20];
//...
switch (type) {
  //...
  case 's':
    // Figure out the length of the target string...
    sscanf(serialized + start, "%d", &len);
    // <code type='graceful'>
    // increment start by the STRING LENGTH of whatever %d was
    // </code>
    // Don't forget to skip over the colon...
    ++start;
    // Build a format string which accounts for length...
    sprintf(format, "%%%ds", len);
    // Finally, grab the target string...
    sscanf(serialized + start, format, string);
    break;
  //...
}

Этот код примерно взят из того, что у меня есть (который не завершен из-за рассматриваемой проблемы), но он должен понять суть. Может быть, я принимаю неправильный подход полностью. Какой самый изящный способ сделать это? Решение может быть C или C ++ (и я бы хотел увидеть конкурирующие методы, если ответов будет достаточно).

Ответы [ 6 ]

8 голосов
/ 09 декабря 2010

Вы можете использовать спецификатор преобразования %n, который не потребляет никакого ввода - вместо этого он ожидает параметр int * и записывает в него число символов, потребляемых из ввода:

int consumed;

sscanf(serialized + start, "%d%n", &len, &consumed);
start += consumed;

(но не забудьте проверить, что sscanf() вернул> 0!)

1 голос
/ 09 декабря 2010

Вот решение C ++, оно могло бы быть лучше и жестко запрограммировано специально для того, чтобы иметь дело с вашим примером ввода, но для его работы не требуется особых изменений.

std::stringstream ss;

char type;
unsigned length;
char dummy;
std::string value;

ss << "s5:Helloxxxxxxxxxxx";

ss >> type;
ss >> length;
ss >> dummy;
ss.width(length);
ss >> value;

std::cout << value << std::endl;

Отказ от ответственности:

Я нуб на C ++.

1 голос
/ 09 декабря 2010

Используйте спецификатор формата %n, чтобы записать количество прочитанных символов в целочисленный аргумент.

0 голосов
/ 10 декабря 2010

Похоже, что формат слишком задан ... (используя поле переменной длины для указания длины поля переменной длины).

Если вы используете GCC, я бы предложил

if (sscanf(serialized,"%c%d:%as",&type,&len,&dest)<3) return -1;
/* use type, dest; ignore len */
free(dest);
return 0;
0 голосов
/ 09 декабря 2010

если вы замените двоеточие пробелом, scanf остановится на нем, и вы можете получить размер malloc, а затем запустить другой scanf, чтобы получить оставшуюся строку

int main (int argc, const char * argv[]) {
char foo[20];
char *test;

scanf("%s",foo); //"hello world"
printf("foo = %s\n", foo);//prints hello
//get size
    test = malloc(sizeof(char)* 10);//replace 10 with your string size
    scanf("%s", test);
printf("test = %s\n", test);//prints world

return 0;
}

`

0 голосов
/ 09 декабря 2010

Вы, вероятно, можете просто использовать atoi, который будет игнорировать двоеточие.

например. len = atoi (сериализовано + начало);

Единственное, что касается atoi, это то, что если он возвращает ноль, это может означать, что преобразование не выполнено или длина действительно равна нулю. Так что это не всегда самая подходящая функция.

...