Разбор строки прогресса в C - PullRequest
5 голосов
/ 11 октября 2008

У меня есть следующая строка символов:

"..1....10..20....30...40....50...80..." 

и мне нужно извлечь все числа из него в массив.

Каков наилучший способ сделать это в C?

Ответы [ 4 ]

11 голосов
/ 11 октября 2008

Возможно, самый простой способ - это использовать функцию strtok() (или strtok_r(), если важен повторный вход):

char str[] = "..1...10...20";
char *p = strtok(str, ".");
while (p != NULL) {
    printf("%d\n", atoi(p));
    p = strtok(NULL, ".");
}

Получив результаты вызова atoi(), легко сохранить эти целые числа в массив.

4 голосов
/ 11 октября 2008

Вы можете использовать код sscanf с подавленным присваиванием (% * [.]), Чтобы пропустить точки (или любой другой символ, который вы хотите), и код числа отсканированных символов% n, чтобы переместить указатель строки.

const char *s = "..1....10..20....30...40....50...80...";
int num, nc;

while (sscanf(s, "%*[.]%d%n", &num, &nc) == 1) {
    printf("%d\n", num);
    s += nc;
}
1 голос
/ 11 октября 2008

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

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

#define ARRAY_SIZE 10

size_t store_numbers (const char *s, long *array, size_t elems)
{
  /* Scan string s, returning the number of integers found, delimited by
   * non-digit characters.  If array is not null, store the first elems
   * numbers into the provided array */

  long value;
  char *endptr;
  size_t index = 0;

  while (*s)
  {
    /* Skip any non-digits, add '-' to support negative numbers */
    while (!isdigit(*s) && *s != '\0')
      s++;

    /* Try to read a number with strtol, set errno to 0 first as
     * we need it to detect a range error. */
    errno = 0;
    value = strtol(s, &endptr, 10);

    if (s == endptr) break; /* Conversion failed, end of input */
    if (errno != 0) { /* Error handling for out of range values here */ }

    /* Store value if array is not null and index is within array bounds */
    if (array && index < elems) array[index] = value;
    index++;

    /* Update s to point to the first character not processed by strtol */
    s = endptr;
  }

  /* Return the number of numbers found which may be more than were stored */
  return index;
}

void print_numbers (const long *a, size_t elems)
{
  size_t idx;
  for (idx = 0; idx < elems; idx++) printf("%ld\n", a[idx]);
  return;
}

int main (void)
{
  size_t found, stored;
  long numbers[ARRAY_SIZE];
  found = store_numbers("..1....10..20....30...40....50...80...", numbers, ARRAY_SIZE);

  if (found > ARRAY_SIZE)
    stored = ARRAY_SIZE;
  else
    stored = found;

  printf("Found %zu numbers, stored %zu numbers:\n", found, stored);
  print_numbers(numbers, stored);

  return 0;
}
0 голосов
/ 11 октября 2008

Я предпочитаю использовать strtok в цикле for. Делает это более естественным, хотя синтаксис выглядит немного странно.

char str[] = "..1....10..20....30...40....50...80..."
for ( char* p = strtok( strtok, "." ); p != NULL; p = strtok( NULL, "." ) )
{
    printf( "%d\n", atoi( p ) );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...