Какова цель использования нотации [^ в scanf? - PullRequest
5 голосов
/ 20 апреля 2009

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

      #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 содержит соответствующую информацию, но у меня проблемы с ее чтением. Какова цель использования такого рода обозначений? Чего это пытается достичь?

Ответы [ 4 ]

6 голосов
/ 20 апреля 2009

Основная причина для классов символов заключается в том, что нотация% 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 не-новых символов, и они назначаются в буфер вместе с завершающим нулем. Второй спецификатор формата, %*[^\n], содержит символ подавления присваивания (*) и считывает ноль или более оставшихся символов без перевода строки из входных данных. Когда функция scanf() завершается, ввод указывает на следующий символ новой строки. Тело цикла считывает и печатает этот символ, так что, когда цикл перезапускается, ввод смотрит на начало следующей строки. Затем процесс повторяется. Если строка короче 10 символов, то эти символы копируются в буфер, а формат «ноль или более не-новых строк» ​​обрабатывает ноль не-новых строк.

4 голосов
/ 20 апреля 2009

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

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

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

2 голосов
/ 20 апреля 2009

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

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

0 голосов
/ 08 ноября 2016

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

Вот параграф, который я цитирую из документа о [ (стр. 286):

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

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

...