Определить слишком длинную строку в scanf () по заданному набору параметров сканирования - PullRequest
0 голосов
/ 01 декабря 2018

Сценарий:
Я пытаюсь подтвердить ввод данных пользователем.В моем случае пользователю разрешено вводить только от 0 до 3 строчных букв, опционально включая пробелы.В регулярном выражении: ^[a-z ]{0,3}$
Если пользователь вводит более 3 символов или входная строка содержит недопустимые значения, в каждом случае должно быть напечатано различное значение return и сообщение об ошибке.

ЧтоЯ попытался прочитать входные данные во временный массив символов и определить набор сканирования как 4[a-z ], так что будут прочитаны только правильные символы и еще один символ, чтобы проверить, было ли прочитано максимальное количество требуемых символов.Т.е. если последний элемент в этом временном массиве не пуст, пользовательский ввод был больше 3.

Проблема:
Когда пользователь вводит 3 правильных символа и 4-й неправильный символ,четвертый не будет прочитан, поэтому мы читаем 3 действительных символа, мы «якобы» никогда не читаем недопустимый символ, и длина прочитанного символа также действительна, хотя, конечно, это не так!

Код:

//--------------------------------------
int scan_input(char* char_array)
{
  int status = 0;
  int max_size = 3;
  char temp_array[max_size+1];

  // Print system prompt:
  printf("plain text: ");
  // Read user input:
  status = scanf("%4[a-z ]", temp_array);

  if (temp_array[max_size] != '\0')
  {
    printf("[ERR] too many characters\n");
    return -1;
  }

  if (status != 1)
  {
    printf("[ERR] invalid characters\n");
    return -2;
  }

  strcpy(char_array,temp_array);
  printf("[OK]  Input is valid!\n");
  return 0;
}

Вывод:

$ gcc -Wall -std=c11 application.c && ./a.out 
plain text: abcD
[OK]  Input is valid!

Я благодарен за каждую подсказку, чтобы исправить это слепое пятно!

PS.: Если вы знаете лучший подход к решению этой проблемы, чем при использовании scanf() и scanset, ваши мысли приветствуются!

1 Ответ

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

для проверки ввода пользователя

Отделение ввода от анализа

  • Использование широкого буфера иfgets().

    char buf[80];
    if (fgets(buf, sizeof buf, stdin)) {
      // we have some input
    
  • Затем выполните синтаксический анализ и используйте "%n", который записывает позицию сканирования, для проверки успешности.

      int max_size = 3;
      char temp_array[max_size+1];
      int n = 0;
      temp_array[0] = '\0';
      sscanf(buf, "%3[a-z ]%n", temp_array, &n);
      bool success = buf[n] == '\n' || buf[n] == '\0';
    

Если sscanf() ничего не сканировал, n == 0 и предыдущий temp_array[0] = 0 страхуют нулевой символ .

Если сканирование прошло успешно, n > 0 и код проверяет следующеесимвол.


Альтернативный вариант с scanf()

status = scanf("%3[a-z ]", temp_array);

// When nothing read, form "" string   
if (status != 1) {
  temp_array[0] = '\0';
}

bool success = true;
if (status == EOF) {
  success = false;
} else {
  // consume rest of line, noting if extra junk followed
  int next_ch;
  while ((next_ch = fgetc(stdin)) != '\n' && next_ch != EOF) {
    success = false;  //Extra junk
  }
}
...