Как извлечь все числа из строки, используя только sscanf? - PullRequest
0 голосов
/ 01 декабря 2018

Как извлечь все числа из строки в следующем формате, используя sscanf только в C:

"(3, 2, 4,5, 10)"

Пробелы могут быть вездено не между цифрами, конечно.На каждой позиции может быть 0 или больше пробелов.

Строка должна иметь правильный формат или ее ошибка.«(3,2,» это ошибка, например. Каждый символ, который не является пробелом или частью формата, является ошибкой

Использование только sscanf (не обязательно)

Моя идея,конечно, это цикл while с sscanf, но моя проблема с форматированием

РЕДАКТИРОВАТЬ: Количество чисел в скобках может быть разным, поэтому мы можем иметь 0 чисел или n чисел в скобках.быть любым числом. (a, a + 1, ..., a + n).

EDIT2: Конечно, разрешено использовать все, что включено в stdio.h, но нет библиотек extendet

1 Ответ

0 голосов
/ 01 декабря 2018

Преамбула

Кажется, что формат данных можно суммировать как: пробел где угодно;открывающая скобка, за которой следует последовательность из одного или нескольких простых целых чисел (без знаков, без десятичных точек), разделенных запятыми и оканчивающихся закрывающей скобкой.Кроме того, между ( и ).

могут быть нулевые целые числа. Данные должны обрабатываться с использованием sscanf();не существует установленного правила для одного звонка на sscanf().Одним из преимуществ использования sscanf() перед альтернативами файлового ввода-вывода (scanf(), fscanf() и т. Д.) Является то, что при необходимости вы можете повторить сканирование.

Обратите внимание, что семейство scanf()не очень хорошо обрабатывает «необязательный элемент».Пробелы в основном тривиальны - все спецификаторы преобразования, кроме %c, %[…] (наборы сканирования) и %n, пропускают начальные пробелы, а символ пробела в строке формата соответствует нулю или большему количеству символов пробела во входных данных.

Код

Функция string_analyzer() выполняет свою работу;он имеет скромно сложный интерфейс, потому что сам не выполняет ввод-вывод - он анализирует строку и добавляет числа в структуру массива, которая передается в функцию.Он также устанавливает сообщение, которое немного говорит вызывающей стороне о том, что пошло не так.Другими функциями являются вспомогательные функции (для типа struct int_array) и тестовый жгут (main() plus test_string_analyzer()).

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct int_array
{
    char   *base;
    size_t  maxlen;
    size_t  curlen;
};

static void dump_int_array(const char *tag, const struct int_array *array);
static void add_to_int_array(struct int_array *array, int data);
static void free_int_array(struct int_array *array);
static void test_string_analyzer(const char *str);

static int string_analyzer(const char *str, struct int_array *array, char **msg)
{
    int offset;
    int length = strlen(str);
    int data;
    char trailer;

    if (sscanf(str, " ( %[)] %n", &trailer, &offset) == 1)
    {
        /* Empty list */
        assert(trailer == ')');
        if (offset == length)
        {
            *msg = "it is an empty list";
            return 0;
        }
        else
        {
            *msg = "it has extra characters after an empty list";
            return -1;
        }
    }

    if (sscanf(str, " ( %d %c%n", &data, &trailer, &offset) != 2 ||
        (trailer != ',' && trailer != ')'))
    {
        *msg = "it does not start correctly";
        return -1;
    }
    add_to_int_array(array, data);
    if (trailer == ')' && offset == length)
    {
        *msg = "it is valid";
        return 0;
    }
    const char *source = str + offset;
    while (sscanf(source, "%d %[,)] %n", &data, &trailer, &offset) == 2)
    {
        add_to_int_array(array, data);
        length = strlen(source);
        if (trailer == ')' && offset == length)
        {
            *msg = "it is valid";
            return 0;
        }
        else if (trailer == ')')
        {
            *msg = "it does not end correctly";
            return -1;
        }
        source += offset;
    }
    *msg = "it is incorrectly formatted";
    return -1;
}

int main(void)
{
    const char *samples[] =
    {
        /* Valid */
        " (3, 2, 4,5, 10 )",
        " ( 4 , 6 ) ",
        "(4)",
        "()",
        /* random -n 15 10 99 | commalist -t -B 8 -b '"( ' -T ' )",' */
        "( 65, 83, 81, 60, 61, 23, 48, 89, 67, 27, 73, 25, 92, 13, 67 )",
        /* Invalid */
        " (3,2, ",
        "3,2",
        " (3,2,1) apathy",
        " () apathy",
        " (3,X,1)",
        " (3X,1)",
    };
    enum { NUM_SAMPLES = sizeof(samples) / sizeof(samples[0]) };

    for (int i = 0; i < NUM_SAMPLES; i++)
        test_string_analyzer(samples[i]);

    return 0;
}

static void test_string_analyzer(const char *str)
{
    struct int_array array = { 0, 0, 0 };
    char *msg = 0;

    printf("Analyzing [%s]\n", str);
    int rc = string_analyzer(str, &array, &msg);
    if (rc == 0)
        printf("String '%s' OK: %s\n", str, msg);
    else
        printf("String '%s' is misformatted: %s\n", str, msg);
    dump_int_array("List contents", &array);

    free_int_array(&array);
}

static void dump_int_array(const char *tag, const struct int_array *array)
{
    int length = printf("%s (%zu): ", tag, array->curlen);
    const char *pad = "";
    for (size_t i = 0; i < array->curlen; i++)
    {
        length += printf("%s%d", pad, array->base[i]);
        pad = ", ";
        if (length >= 64)
        {
            pad = "    ";
            length = 0;
            putchar('\n');
        }
    }
    if (length > 0)
        putchar('\n');
}

static void add_to_int_array(struct int_array *array, int data)
{
    if (array->curlen >= array->maxlen)
    {
        assert(array->curlen == array->maxlen);
        size_t newlen = array->maxlen * 2 + 2;
        void  *newarr = realloc(array->base, newlen * sizeof(array->base[0]));
        if (newarr == NULL)
        {
        }
        array->base = newarr;
        array->maxlen = newlen;
    }
    array->base[array->curlen++] = data;
}

static void free_int_array(struct int_array *array)
{
    free(array->base);
    array->base = 0;
    array->maxlen = 0;
    array->curlen = 0;
}

Пример вывода:

Analyzing [ (3, 2, 4,5, 10 )]
String ' (3, 2, 4,5, 10 )' OK: it is valid
List contents (5): 3, 2, 4, 5, 10
Analyzing [ ( 4 , 6 ) ]
String ' ( 4 , 6 ) ' OK: it is valid
List contents (2): 4, 6
Analyzing [(4)]
String '(4)' OK: it is valid
List contents (1): 4
Analyzing [()]
String '()' OK: it is an empty list
List contents (0): 
Analyzing [( 65, 83, 81, 60, 61, 23, 48, 89, 67, 27, 73, 25, 92, 13, 67 )]
String '( 65, 83, 81, 60, 61, 23, 48, 89, 67, 27, 73, 25, 92, 13, 67 )' OK: it is valid
List contents (15): 65, 83, 81, 60, 61, 23, 48, 89, 67, 27, 73, 25
    92, 13, 67
Analyzing [ (3,2, ]
String ' (3,2, ' is misformatted: it is incorrectly formatted
List contents (2): 3, 2
Analyzing [3,2]
String '3,2' is misformatted: it does not start correctly
List contents (0): 
Analyzing [ (3,2,1) apathy]
String ' (3,2,1) apathy' is misformatted: it does not end correctly
List contents (3): 3, 2, 1
Analyzing [ () apathy]
String ' () apathy' is misformatted: it has extra characters after an empty list
List contents (0): 
Analyzing [ (3,X,1)]
String ' (3,X,1)' is misformatted: it is incorrectly formatted
List contents (1): 3
Analyzing [ (3X,1)]
String ' (3X,1)' is misformatted: it does not start correctly
List contents (0): 
...