Какова цель использования обозначения [^ в scanf?
-
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 ^, ни последним символом, поведение определяется реализацией.