Используйте scanf с регулярными выражениями

Я пытался использовать регулярные выражения в scanf, чтобы прочитать строку из максимум n символов и отбросить все остальное до символа новой строки. Любые пробелы следует рассматривать как обычные символы и включать их в читаемую строку. Я изучил статью в Википедии о регулярных выражениях, но не могу заставить scanf работать должным образом. Вот код, который я пробовал:

scanf("[ ]*%ns[ ]*[\n]", string);

[] должен указывать на фактический пробел, * должен означать один или несколько, n - количество символов для чтения, а строка - это указатель, выделенный с помощью malloc. Я пробовал несколько разных комбинаций; однако я стараюсь читать только первое слово предложения (останавливается на пробеле). Кроме того, * кажется, что отбрасывает символ вместо того, чтобы означать «ноль или более» ...

Может ли кто-нибудь подробно объяснить, как регулярные выражения интерпретируются scanf? Более того, эффективно ли вместо этого многократно использовать getc?

Заранее спасибо


person someone    schedule 14.02.2013    source источник
comment
Попробуйте fgets(): fgets(string, sizeof string, stdin);   -  person pmg    schedule 15.02.2013
comment
Проблема в том, что любые оставшиеся символы останутся во входном потоке, не так ли?   -  person someone    schedule 15.02.2013
comment
Если достаточно места, fgets() потребляет все до (включительно) a '\n'.   -  person pmg    schedule 15.02.2013
comment
Не используйте scanf.   -  person zwol    schedule 15.02.2013


Ответы (3)


Краткий ответ: scanf не обрабатывает регулярные выражения буквально.

Если вы хотите использовать регулярные выражения в C, вы можете использовать библиотеку регулярных выражений POSIX. См. Базовый пример использования этой библиотеки в следующем вопросе: Регулярные выражения в C: примеры?

Теперь, если вы хотите сделать это scanf способом, вы можете попробовать что-нибудь вроде

scanf("%*[ ]%ns%*[ ]\n",str);

Замените n в %ns максимальным количеством символов для чтения из входного потока. Часть %*[ ] просит игнорировать любые пробелы. Вы можете заменить * определенным числом, чтобы игнорировать точное количество символов. Вы можете добавить другие символы между фигурными скобками, чтобы игнорировать больше, чем просто пробелы.

Не уверен, что указанный выше scanf будет работать, поскольку пробелы также совпадают с директивой %s.
Я бы определенно пошел с вызовом fgets, а затем обрезал окружающие пробелы примерно следующим образом:
Как обрезать ведущие / конечные пробелы стандартным способом?

person greydet    schedule 14.02.2013
comment
Итак, в конце концов, нет другого способа отбросить оставшийся ввод? Я думал об использовании getc многократно, сохраняя необходимое мне количество символов и отбрасывая остальную часть строки, пока не будет найден символ \ n ... - person someone; 15.02.2013
comment
Я отредактировал свой ответ одновременно с вашим комментарием. Так что да, можно игнорировать некоторые вводимые данные, но я бы не стал называть строку формата scanf регулярным выражением. - person greydet; 15.02.2013
comment
Спасибо за Ваш ответ! Однако можете ли вы объяснить семантику того, что вы там использовали? - person someone; 15.02.2013
comment
Спасибо за вашу помощь! Я очень ценю это. : D - person someone; 15.02.2013
comment
Извините за повторный вопрос, но я проверил предоставленную вами строку формата безрезультатно. Я пробовал этот код: #include ‹stdio.h› int main () {char sth [10], any [1024]; scanf (% * []% 9s% * [] \ n, sth); printf (1% s, sth); getchar (); scanf (% s, любой); printf (2% s, любое); возврат 0; } Попробуйте использовать в качестве входных данных что-нибудь еще. Вы получаете 12 ничего вместо 1 что-нибудь 2 ... - person someone; 15.02.2013
comment
Да, я так подумал, в своем ответе я предложил другое решение. - person greydet; 15.02.2013
comment
В ПОРЯДКЕ! В конце концов, я решил использовать вместо этого getc ... Все равно спасибо! - person someone; 15.02.2013
comment
@greydet: У меня проблемы с получением первого сервера имен в /etc/resolv.conf с помощью одного fscanf. Я пробовал fscanf(fp,"%*nameserver:%20[^\n]",address);, который возвращает 0 (результатов не найдено); И address пусто. (Да, файл был успешно открыт ранее с помощью fopen). - person user2284570; 26.02.2014

Эффективно ли вместо этого многократно использовать getc?

В некоторой степени зависит от приложения, но ДА, повторение getc() эффективно.

person pmg    schedule 14.02.2013

если я не прочитал вопрос неправильно,% [^ '\ n'] s сохранит все до тех пор, пока не встретится возврат каретки.

person user1391596    schedule 01.01.2016
comment
s в %[^'\n']s не требуется. - person chux - Reinstate Monica; 28.06.2016