Какова цель использования обозначения [^ в scanf?

StackOverflow https://stackoverflow.com/questions/766516

  •  12-09-2019
  •  | 
  •  

Вопрос

Я наткнулся на какой-то код, и мне было интересно, чем занимался первоначальный разработчик.Ниже приведена упрощенная программа, использующая этот шаблон:

      #include <stdio.h>

      int main()  {     

      char title[80] = "mytitle";      
      char title2[80] = "mayataiatale";      
      char mystring[80]; 

      /* hugh ? */
      sscanf(title,"%[^a]",mystring);
      printf("%s\n",mystring); /* Output is "mytitle" */


      /* hugh ? */
      sscanf(title2,"%[^a]",mystring); /* Output is "m" */
      printf("%s\n",mystring);


      return 0;  
  }

Тот Самый справочная страница для scanf содержит соответствующую информацию, но у меня возникли проблемы с ее чтением.Какова цель использования такого рода обозначений?Чего он пытается достичь?

Это было полезно?

Решение

Основная причина для символьных классов заключается в том, что обозначение %s останавливается на первом символе пробела, даже если вы указываете длину поля, а вы довольно часто этого не хотите.В этом случае обозначение символьного класса может быть чрезвычайно полезным.

Используйте этот код для чтения строки длиной до 10 символов, отбрасывая все лишнее, но сохраняя пробелы:

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

int main(void)
{
    char buffer[10+1] = "";
    int rc;
    while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
    {
            int c = getchar();
            printf("rc = %d\n", rc);
            if (rc >= 0)
                    printf("buffer = <<%s>>\n", buffer);
            buffer[0] = '\0';
    }
    printf("rc = %d\n", rc);
    return(0);
}

На самом деле это был пример кода для обсуждения на comp.lang.c.moderated (примерно в июне 2004), связанного с getline() варианты.


По крайней мере, царит некоторая неразбериха.Первый спецификатор формата, %10[^\n], считывает до 10 символов, отличных от перевода строки, и они присваиваются буферу вместе с завершающим значением null.Второй спецификатор формата, %*[^\n] содержит символ подавления присвоения (*) и считывает ноль или более оставшихся символов, отличных от перевода строки, из входных данных.Когда scanf() функция завершается, входные данные указывают на следующий символ новой строки.Тело цикла считывает и печатает этот символ, так что при перезапуске цикла входные данные отображаются в начале следующей строки.Затем процесс повторяется.Если строка короче 10 символов, то эти символы копируются в буфер, и формат "ноль или более не-новых строк" обрабатывает ноль не-новых строк.

Другие советы

Конструкции , подобные %[a] и %[^a] существовать так, чтобы scanf() может использоваться как своеобразный лексический анализатор.Это что - то вроде %s, но вместо того, чтобы собирать диапазон из как можно большего количества "тягучих" символов, они собирают только диапазон символов, как описано в классе character.Могут быть случаи, когда написание %[a-zA-Z0-9] возможно, это имеет смысл, но я не уверен, что вижу убедительный вариант использования дополнительных классов с scanf().

ИМХО, scanf() это просто неподходящий инструмент для этой работы.Каждый раз, когда я намеревался использовать одну из его более мощных функций, в конечном итоге я вырывал ее и реализовывал по-другому.В некоторых случаях это означало использование lex для написания реального лексического анализатора, но обычно выполнение ввода-вывода по строкам за раз и грубое разбиение его на токены с strtok() до этого было достаточно выполнить преобразование значений.

Редактировать: Я закончил вырываться scanf() как правило, потому, что, сталкиваясь с пользователями, настаивающими на предоставлении неверных входных данных, это просто не помогает программе дать хороший отзыв о проблеме, и ассемблер выводит "Ошибка, завершено". поскольку его единственное полезное сообщение об ошибке не понравилось моему пользователю.(В таком случае, я.)

Это как наборы символов из регулярных выражений; [0-9] соответствует строке цифр, [^aeiou] соответствует всему, что не является гласной в нижнем регистре, и т.д.

Существуют всевозможные способы использования, такие как извлечение чисел, идентификаторов, фрагментов пробелов и т.д.

Вы можете прочитать об этом в Стандарт ISO/IEC9899 доступно онлайн.

Вот абзац, который я цитирую из документа о [ (Страница 286):

Соответствует непустой последовательности символов из набора ожидаемых символов.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top