Как использовать set scanset в sscanf для чтения чисел вроде 0-9 - PullRequest
0 голосов
/ 31 августа 2018

Как читать входные данные с помощью набора сканирования, например [0-9] или [a-z], в функции sscanf в C. Мы не смогли успешно реализовать набор сканирования для успешного сканирования через строку.

Это мой пример:

void printResult(char * test, char * actual, char * expected)
{
    printf("\n\n%d. %s\r",testcount++, test);

    if(strcmp(actual,expected) == 0)
{
    printf("SUCCESS\r");
    printf("Output:%s", actual);
}
else
{
    printf("FAILED\r");
    printf("Expected Output:%s   Actual Output:%s", expected, actual);
    }
    }
    int main()
  {
    char buffer[] = "250MEL\r";
    char * pBuffer = buffer;
    char output[5]={0};
    //1 
    sscanf(pBuffer,"%[ 0-9 ]s",output);
    printResult("%[0-9]s", output, "250");

    //2
    sscanf(pBuffer,"%3[ 0-9 ]s",output);
    printResult("%3[0-9]s", output, "250");


    return 0;
    }

Можете ли вы помочь мне правильно использовать скансет.

1 Ответ

0 голосов
/ 01 сентября 2018

TL; DR Непонятно, что заставляет вас думать, что ваши наборы сканирования не сработали; они работают нормально в этом контексте для меня. Мягко модифицированный код, показанный ниже, демонстрирует это.

Как я отмечал в комментарии , набор сканирования имеет вид %[…] - он останавливается на ] и все, что следует (s в коде в вопросе), не является часть набора сканирования. Если вам нужно включить ] в набор сканирования, это должен быть первый символ (после каретки, которая отменяет набор сканирования, если вы используете набор сканирования с отрицанием). С s после набора сканирования, если вход включает s после конца цифры и последовательности пробелов (первый пробел в наборе сканирования значим; второй, будучи повторением, нет), тогда этот символ будет «потреблен», и следующая операция ввода продолжится после s; если следующий символ не является s, то он остается на входе для следующей операции ввода. Кроме того, если следующий символ не является s, сопоставление завершается неудачно, но sscanf() не может сообщить об этом, когда набор сканирования является последней или единственной спецификацией преобразования в строке формата. Конечный контекст всегда расходуется; его отсутствие не может быть обнаружено.

Ваш код любопытен тем, что он использует \r в нескольких местах. Вам редко нужно будет использовать \r в коде C - вы должны использовать \n в своем коде (или пробелах, или ...).

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

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

static int testcount = 1;

static void printResult(char *test, char *actual, char *expected)
{
    printf("\n\n%d. [%s]: ", testcount++, test);

    if (strcmp(actual, expected) == 0)
    {
        printf("SUCCESS  ");
        printf("Output: [%s]\n", actual);
    }
    else
    {
        printf("FAILED  ");
        printf("Expected Output: [%s], Actual Output: [%s]\n", expected, actual);
    }
}

int main(void)
{
    char buffer[] = "250MEL\r";
    char *pBuffer = buffer;
    char output[5] = {0};
    // 1
    if (sscanf(pBuffer, "%[ 0-9 ]s", output) != 1)
        printf("scanf() 1 failed\n");
    printResult("%[ 0-9 ]s", output, "250");

    // 2
    if (sscanf(pBuffer, "%3[ 0-9 ]s", output) != 1)
        printf("scanf() 1 failed\n");
    printResult("%3[ 0-9 ]s", output, "250");

    return 0;
}

Также выдает ожидаемый результат:

1. [%[ 0-9 ]s]: SUCCESS  Output: [250]


2. [%3[ 0-9 ]s]: SUCCESS  Output: [250]

Если раньше вы не видели SUCCESS, то это потому, что символ \r перемещает позицию записи в начало строки, поэтому последующее переписывание SUCCESS.

Вспомогательный вопрос

Также, пожалуйста, дайте мне знать, как я могу установить диапазон для A-Z, как показано ниже - но это не работает:

sscanf(pBuffer,"%*[A-Z]s",output);
printResult("%[A-Z]s",output, "MEL" );

Пожалуйста Обратите внимание!

Ваш комментарий показывает, что вы все еще думаете, что %[…]s является обозначением для набора сканирования, но s является ложным; это не часть нотации набора сканирования. Хватит думать о %[…] как о модификаторе %s; это не модификатор. Это полностью независимая спецификация преобразования, почти полностью не связанная и синтаксически совершенно отличная от %s. Обозначение в квадратных скобках также категорически и однозначно не является частью какого-либо стандартного синтаксиса спецификации преобразования printf().

Вот некоторый пересмотренный код, в значительной степени основанный на предыдущей части ответа (и, следовательно, на коде в вопросе). Он не звездный, но показывает некоторую полезную информацию.

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

static int strings_match(const char *actual, const char *expected);
static void printResult(const char *format, const char *data, const char *act1,
                        char *exp1, const char *act2, char *exp2);

int main(void)
{
    char buffer1[] = "250MEL@93";
    char buffer2[] = "  250   \t\tMELabc";
    char number[5] = "";
    char letters[5] = "";
    const char fmt1[] = "%4[0-9]%4[A-Z]";
    const char fmt2[] = " %4[0-9] %4[A-Z]";

    if (sscanf(buffer1, fmt1, number, letters) != 2)
        printf("sscanf() 1 failed\n");
    else
        printResult(fmt1, buffer1, number, "250", letters, "MEL");

    if (sscanf(buffer2, fmt2, number, letters) != 2)
        printf("sscanf() 2 failed\n");
    else
        printResult(fmt2, buffer2, number, "250", letters, "MEL");

    number[0] = '\0';
    letters[0] = '\0';
    if (sscanf(buffer2, fmt1, number, letters) != 2)
        printf("sscanf() 3 failed\n");
    else
        printResult(fmt2, buffer1, number, "250", letters, "MEL");

    const char fmt3[] = "%4[0-9]s%c";
    const char fmt4[] = "%4[0-9]%c";
    char buffer3[] = "9876sun";
    char buffer4[] = "9876moon";
    char letter;

    if (sscanf(buffer3, fmt3, number, &letter) != 2)
        printf("sscanf() 4 failed\n");
    else
        printf("Data [%s], Format [%s], Output [%s] %c\n", buffer3, fmt3, number, letter);

    if (sscanf(buffer3, fmt4, number, &letter) != 2)
        printf("sscanf() 5 failed\n");
    else
        printf("Data [%s], Format [%s], Output [%s] %c\n", buffer3, fmt4, number, letter);

    if (sscanf(buffer4, fmt3, number, &letter) != 2)
        printf("sscanf() 6 failed\n");
    else
        printf("Data [%s], Format [%s], Output [%s] %c\n", buffer4, fmt3, number, letter);

    return 0;
}

static int strings_match(const char *actual, const char *expected)
{
    int rc;
    if (strcmp(actual, expected) == 0)
    {
        rc = 1;
        printf(" Output: [%s]", actual);
    }
    else
    {
        rc = 0;
        printf(" Expected Output: [%s], Actual Output: [%s]", expected, actual);
    }
    return rc;
}

static int testcount = 1;

static void printResult(const char *format, const char *data, const char *act1,
                        char *exp1, const char *act2, char *exp2)
{
    printf("Format: %d. [%s] Data: [%s]", testcount++, format, data);
    int t1 = strings_match(act1, exp1);
    int t2 = strings_match(act2, exp2);

    if (t1 == 1 && t2 == 1)
        printf(" - SUCCESS\n");
    else
        printf(" - FAILED\n");
}

Выход:

Format: 1. [%4[0-9]%4[A-Z]] Data: [250MEL@93] Output: [250] Output: [MEL] - SUCCESS
Format: 2. [ %4[0-9] %4[A-Z]] Data: [  250          MELabc] Output: [250] Output: [MEL] - SUCCESS
sscanf() 3 failed
Data [9876sun], Format [%4[0-9]s%c], Output [9876] u
Data [9876sun], Format [%4[0-9]%c], Output [9876] s
sscanf() 6 failed

Обратите внимание, как отличаются две последние успешные строки преобразования - s в строке формата сопоставляется как литерал с данными, оставляя u для чтения в символ по сравнению с отсутствием s в строке формата и символ соответствует s. Напротив, когда формат ищет s и находит m, общий sscanf() дает сбой - он управляет только 1 вместо 2 спецификаций преобразования.

...