игнорирование пробелов с помощью Sscanf в C - PullRequest
2 голосов
/ 14 марта 2011

У меня есть строка, такая как "4 Tom Tim 6", и я пытаюсь просмотреть эти значения с помощью sscanf, как это sscanf (строка, "% d% s% d", & NUMBER1, NAME, & number2)

есть ли способ сделать это и внести в NUMBER1 значение 4, в NUMBER2 значение 6 и в NAME значение "Tom Tim"?

Я пытался, но sscanf разделяет "Tom" и "Tim", потому что между ними есть пробел, и поэтому он также возвращает неверное значение для NUMBER2.

Обновление:

Позвольте мне быть более конкретным. Всегда будет число в начале и в конце строки my и подстрока между этими числами, которая может иметь любую длину и любое количество пробелов, и я пытаюсь получить эту подстроку в одной переменной, и цифры в начале и в конце.

Ответы [ 7 ]

5 голосов
/ 14 марта 2011

Вы читаете это как

sscanf(string, "%d %s %s %d", &NUMBER1, &NAME, &SECONDNAME, &NUMBER2);

затем объединить их

strcat(NAME," "); // Add space
strcat(NAME,SECONDNAME); // Add second name

Убедитесь, что в NAME достаточно места для хранения как имени, так и имени. Вам также придется:

#include <string.h>
4 голосов
/ 14 марта 2011

Чтобы найти решение (и сказать, возможно ли это даже с sscanf), вам нужно предоставить больше информации о формате вашей строки.Невозможно получить что-либо убедительное из одного приведенного вами примера.

В вашем конкретном случае нужно знать, где заканчивается имя и начинается следующий номер.Как вы определяете это в вашем случае?Должны ли мы предполагать, что первый десятичный символ означает конец имени и начало number2?Или это что-то более сложное?Если входная строка содержит последовательность "Tom16", предполагается ли имя целиком "Tom16" или мы должны разделить его на "Tom" и оставить 16 для number2?

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

Обновление: Ваше описание формата строки еще далеко от завершения, но я могу предложитьиспользование следующего спецификатора формата в sscanf

sscanf(string, "%d %[^0123456789]%d", &number1, name, &number2)

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

В любом случае, возможности разбора sscanf довольно ограничены.Как правило, они не подходят для решения проблемы, как ваша.То, что я имею выше, вероятно, лучшее, что вы можете получить из sscanf.Если вам нужно что-то еще более сложное, вам придется анализировать вашу строку вручную, токен за токеном, вместо того, чтобы пытаться проанализировать все это в одном кадре с sscanf.

3 голосов
/ 14 марта 2011

Нет, не с sscanf().
Вы можете сделать это «легко» с помощью fgets() и анализируя строку за символом


/* basic incomplete version; no error checking; name ends with whitespace */

#include <ctype.h>
#include <stdio.h>

  int num1, num2;
  char name[250], line[8192], *p;

  fgets(line, sizeof line, stdin);
  num1 = num2 = 0;
  p = line;
  while (isdigit((unsigned char)*p) {num1 = num1*10 + *p - '0'; p++};
  while (isspace((unsigned char)*p)) p++;
  while (!isdigit((unsigned char)*p)) *name++ = *p++;
  while (isdigit((unsigned char)*p) {num2 = num2*10 + *p - '0'; p++};
2 голосов
/ 14 марта 2011

Вы не можете выполнить эту работу с функцией sscanf и «центральной» строкой с произвольным числом пробелов в ней, поскольку пробел также является вашим разделителем для следующего поля; если бы это %s соответствовало строкам с пробелами, оно "съело бы" также 6.

Если только ваше «центральное» поле является «специальным», и у вас есть только эти три поля, вы должны прочитать свою строку в обратном направлении, чтобы найти начало третьего поля, и преобразовать его в число; затем вы заменяете символ перед 6 на \0, таким образом обрезая строку перед третьим полем.

Затем вы можете использовать strtoul, чтобы преобразовать первое поле и определить, где оно заканчивается (используя его второй параметр); учитывая строку, которая начинается там и идет до конца усеченной строки, вы получаете второе поле.

1 голос
/ 14 марта 2011

@ AndreyT в значительной степени правильно.Я собираюсь угадать, что среднее поле должно останавливаться на любой цифре.Если это так, то да sscanf может выполнить эту работу:

sscanf(string, "%d %[^0-9] %d", &NUMBER1, NAME, &number2);

Вы действительно хотите ограничить количество считываемых данных длиной вашего буфера, хотя:

char name[32];
sscanf(string, "%d %31[^0-9] %d", &number1, name, &number2);

Я должен добавить, что технически это не портативный как есть.Чтобы быть полностью переносимым, вы должны использовать [^0123456789] вместо [^0-9].Старые версии компиляторов Borland фактически обрабатывали «0-9» как означающие три символа «0», «-» и «9».Стандарт разрешает это, хотя я не знаю ни одного текущего компилятора, который считает свое разрешение глупым.

0 голосов
/ 14 марта 2011

Я могу придумать пару способов:

1) Если вы всегда знаете размер поля «Том Тим», используйте формат% c с указателем длины:

int num1;
int num2;
char name[8];

sscanf(string, "%d %7c %d", &num1, name, &num2);
name[7] = '/0';

Обратите внимание, что NAME должно быть достаточно большим, чтобы удерживать прочитанные символы, и чтобы оно не заканчивалось нулем, поэтому это необходимо сделать вручную.

2) Если вы знаете, что всегда есть два поля, используйте два строковых спецификатора и strncat () их вместе:

char name1[40];
char name2[20];
int num1;
int num2;
sscanf(string, "%d %s %s %d", &num1, name1, name2, &num2);
strncat(name1, name2, sizeof(name2)-1);

Вы также можете проанализировать строку, используя strtok_r (). Я оставлю это как упражнение для читателя.

0 голосов
/ 14 марта 2011

Вы могли бы:

sscanf(string, "%d %s %s %d", &NUMBER1, NAME1 , NAME2, &number2 );
strcat(NAME , NAME1);
strcat(NAME , " ");
strcat(NAME , NAME2);

Но это приведет к неопределенному поведению, если NAME недостаточно велико.

...