В ANSI C нет встроенной поддержки регулярных выражений. Какую библиотеку регулярных выражений вы используете?
Джо
7
Роб Пайк написал небольшую функцию поиска строк регулярного выражения, которая приняла очень полезное подмножество регулярных выражений для книги «Практика программирования», соавтором которой он и Брайан Керниган были . См. Это обсуждение, « Сопоставление
Ричард Чамберс,
Ответы:
233
Регулярные выражения на самом деле не являются частью ANSI C. Возможно, вы говорите о библиотеке регулярных выражений POSIX, которая поставляется с большинством (все?) * Nixes. Вот пример использования регулярных выражений POSIX в C (на основе этого ):
#include<regex.h>regex_t regex;int reti;char msgbuf[100];/* Compile regular expression */
reti = regcomp(®ex,"^a[[:alnum:]]",0);if(reti){
fprintf(stderr,"Could not compile regex\n");
exit(1);}/* Execute regular expression */
reti = regexec(®ex,"abc",0, NULL,0);if(!reti){
puts("Match");}elseif(reti == REG_NOMATCH){
puts("No match");}else{
regerror(reti,®ex, msgbuf,sizeof(msgbuf));
fprintf(stderr,"Regex match failed: %s\n", msgbuf);
exit(1);}/* Free memory allocated to the pattern buffer by regcomp() */
regfree(®ex);
В качестве альтернативы вы можете попробовать PCRE , библиотеку для Perl-совместимых регулярных выражений на C. Синтаксис Perl в значительной степени аналогичен синтаксису, используемому в Java, Python и ряде других языков. Синтаксис POSIX является синтаксис , используемый grep, sed, viи т.д.
Если вам не нужно избегать зависимости от второго PCRE, он имеет несколько хороших улучшений синтаксиса и очень стабилен. По крайней мере, в некоторых старых версиях Linux «встроенная» библиотека регулярных выражений не слишком сложна для аварийного завершения при определенных входных строках и определенных регулярных выражениях, которые «почти» совпадают или содержат много специальных символов
bdk
@ Laurence Что означает передача 0 для regcomp? regcomp принимает только четыре целых значения 1, 2, 4 и 8 для представления 4 различных режимов.
Лисян
2
@lixiang Последний параметр regcomp, cflagsявляется битовая. Из pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html : «Аргумент cflags является побитовым ИЛИ с нулем или более из следующих флагов ...». Если вы ИЛИ - вместе ноль, вы получите 0. Я вижу, что страница руководства Linux для regcomp«cflags может быть побитовой - или одного или нескольких из следующего», что, похоже, вводит в заблуждение.
Лоуренс Гонсалвес
2
Вы можете извлечь текст из соответствующих групп с помощью чего-то вроде: regmatch_t matches[MAX_MATCHES]; if (regexec(&exp, sz, MAX_MATCHES, matches, 0) == 0) { memcpy(buff, sz + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); printf("group1: %s\n", buff); }обратите внимание, что совпадения групп начинаются с 1, группа 0 - это вся строка. Добавьте проверки ошибок на выход за пределы и т. Д.
Возможно, это не то, что вам нужно, но такой инструмент, как re2c, может компилировать регулярные выражения POSIX (-ish) в ANSI C. Он написан как замена lex, но этот подход позволяет вам пожертвовать гибкостью и удобочитаемостью для последнего бита скорости, если тебе это действительно нужно.
man regex.hсообщает, что для regex.h нет ручного ввода, но man 3 regex дает вам страницу, объясняющую функции POSIX для сопоставления с образцом.
Те же функции описаны в библиотеке GNU C: сопоставление регулярных выражений , в которой объясняется, что библиотека GNU C поддерживает как интерфейс POSIX.2, так и интерфейс, который библиотека GNU C имела в течение многих лет.
Например, для гипотетической программы, которая печатает, какая из строк, переданных в качестве аргумента, соответствует шаблону, переданному в качестве первого аргумента, вы можете использовать код, подобный следующему.
#include<errno.h>#include<regex.h>#include<stdio.h>#include<stdlib.h>#include<string.h>void print_regerror (int errcode,size_t length,regex_t*compiled);int
main (int argc,char*argv[]){regex_t regex;int result;if(argc <3){// The number of passed arguments is lower than the number of// expected arguments.
fputs ("Missing command line arguments\n", stderr);return EXIT_FAILURE;}
result = regcomp (®ex, argv[1], REG_EXTENDED);if(result){// Any value different from 0 means it was not possible to // compile the regular expression, either for memory problems// or problems with the regular expression syntax.if(result == REG_ESPACE)
fprintf (stderr,"%s\n", strerror(ENOMEM));else
fputs ("Syntax error in the regular expression passed as first argument\n", stderr);return EXIT_FAILURE;}for(int i =2; i < argc; i++){
result = regexec (®ex, argv[i],0, NULL,0);if(!result){
printf ("'%s' matches the regular expression\n", argv[i]);}elseif(result == REG_NOMATCH){
printf ("'%s' doesn't the regular expression\n", argv[i]);}else{// The function returned an error; print the string // describing it.// Get the size of the buffer required for the error message.size_t length = regerror (result,®ex, NULL,0);
print_regerror (result, length,®ex);return EXIT_FAILURE;}}/* Free the memory allocated from regcomp(). */
regfree (®ex);return EXIT_SUCCESS;}void
print_regerror (int errcode,size_t length,regex_t*compiled){char buffer[length];(void) regerror (errcode, compiled, buffer, length);
fprintf(stderr,"Regex match failed: %s\n", buffer);}
Последний аргумент regcomp()должно быть по крайней мере REG_EXTENDED, или функции будут использовать основные регулярные выражения , что означает , что (например), нужно будет использовать a\{3\}вместо a{3}использовать из расширенных регулярных выражений , которые, вероятно , что вы собираетесь использовать.
POSIX.2 также имеет другую функцию группового символа соответствия: fnmatch(). Он не позволяет скомпилировать регулярное выражение или получить подстроки, соответствующие подвыражению, но он очень специфичен для проверки соответствия имени файла подстановочному знаку (например, он использует FNM_PATHNAMEфлаг).
Хотя приведенный выше ответ хороший, я рекомендую использовать PCRE2 . Это означает, что вы можете буквально использовать все примеры регулярных выражений, и вам не нужно переводить их с какого-то древнего регулярного выражения.
Я уже ответил на это, но думаю, что и здесь это может помочь.
// YOU MUST SPECIFY THE UNIT WIDTH BEFORE THE INCLUDE OF THE pcre.h#define PCRE2_CODE_UNIT_WIDTH 8#include<stdio.h>#include<string.h>#include<pcre2.h>#include<stdbool.h>int main(){boolDebug=true;boolFound=false;
pcre2_code *re;
PCRE2_SPTR pattern;
PCRE2_SPTR subject;int errornumber;int i;int rc;
PCRE2_SIZE erroroffset;
PCRE2_SIZE *ovector;size_t subject_length;
pcre2_match_data *match_data;char*RegexStr="(?:\\D|^)(5[1-5][0-9]{2}(?:\\ |\\-|)[0-9]{4}(?:\\ |\\-|)[0-9]{4}(?:\\ |\\-|)[0-9]{4})(?:\\D|$)";char* source ="5111 2222 3333 4444";
pattern =(PCRE2_SPTR)RegexStr;// <<<<< This is where you pass your REGEX
subject =(PCRE2_SPTR)source;// <<<<< This is where you pass your bufer that will be checked.
subject_length = strlen((char*)subject);
re = pcre2_compile(
pattern,/* the pattern */
PCRE2_ZERO_TERMINATED,/* indicates pattern is zero-terminated */0,/* default options */&errornumber,/* for error number */&erroroffset,/* for error offset */
NULL);/* use default compile context *//* Compilation failed: print the error message and exit. */if(re == NULL){
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer,sizeof(buffer));
printf("PCRE2 compilation failed at offset %d: %s\n",(int)erroroffset,buffer);return1;}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_match(
re,
subject,/* the subject string */
subject_length,/* the length of the subject */0,/* start at offset 0 in the subject */0,/* default options */
match_data,/* block for storing the result */
NULL);if(rc <0){switch(rc){case PCRE2_ERROR_NOMATCH://printf("No match\n"); //
pcre2_match_data_free(match_data);
pcre2_code_free(re);Found=0;returnFound;// break;/*
Handle other special cases if you like
*/default: printf("Matching error %d\n", rc);//break;}
pcre2_match_data_free(match_data);/* Release memory used for the match */
pcre2_code_free(re);Found=0;/* data and the compiled pattern. */returnFound;}if(Debug){
ovector = pcre2_get_ovector_pointer(match_data);
printf("Match succeeded at offset %d\n",(int)ovector[0]);if(rc ==0)
printf("ovector was not big enough for all the captured substrings\n");if(ovector[0]> ovector[1]){
printf("\\K was used in an assertion to set the match start after its end.\n""From end to start the match was: %.*s\n",(int)(ovector[0]- ovector[1]),(char*)(subject + ovector[1]));
printf("Run abandoned\n");
pcre2_match_data_free(match_data);
pcre2_code_free(re);return0;}for(i =0; i < rc; i++){
PCRE2_SPTR substring_start = subject + ovector[2*i];size_t substring_length = ovector[2*i+1]- ovector[2*i];
printf("%2d: %.*s\n", i,(int)substring_length,(char*)substring_start);}}else{if(rc >0){Found=true;}}
pcre2_match_data_free(match_data);
pcre2_code_free(re);returnFound;}
Установите PCRE, используя:
wget https://ftp.pcre.org/pub/pcre/pcre2-10.31.zip
make
sudo make install
sudo ldconfig
Компиляция с использованием:
gcc foo.c -lpcre2-8-o foo
Проверьте мой ответ для более подробной информации.
Ответы:
Регулярные выражения на самом деле не являются частью ANSI C. Возможно, вы говорите о библиотеке регулярных выражений POSIX, которая поставляется с большинством (все?) * Nixes. Вот пример использования регулярных выражений POSIX в C (на основе этого ):
В качестве альтернативы вы можете попробовать PCRE , библиотеку для Perl-совместимых регулярных выражений на C. Синтаксис Perl в значительной степени аналогичен синтаксису, используемому в Java, Python и ряде других языков. Синтаксис POSIX является синтаксис , используемый
grep
,sed
,vi
и т.д.источник
regcomp
,cflags
является битовая. Из pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html : «Аргумент cflags является побитовым ИЛИ с нулем или более из следующих флагов ...». Если вы ИЛИ - вместе ноль, вы получите 0. Я вижу, что страница руководства Linux дляregcomp
«cflags может быть побитовой - или одного или нескольких из следующего», что, похоже, вводит в заблуждение.regmatch_t matches[MAX_MATCHES]; if (regexec(&exp, sz, MAX_MATCHES, matches, 0) == 0) { memcpy(buff, sz + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); printf("group1: %s\n", buff); }
обратите внимание, что совпадения групп начинаются с 1, группа 0 - это вся строка. Добавьте проверки ошибок на выход за пределы и т. Д.regfree
необходимости после сбояregcomp
, хотя на самом деле она недостаточно конкретизирована, это говорит о том, что этого не следует делать: redhat.com/archives/libvir-list/2013-September/msg00276.htmlВозможно, это не то, что вам нужно, но такой инструмент, как re2c, может компилировать регулярные выражения POSIX (-ish) в ANSI C. Он написан как замена
lex
, но этот подход позволяет вам пожертвовать гибкостью и удобочитаемостью для последнего бита скорости, если тебе это действительно нужно.источник
man regex.h
сообщает, что для regex.h нет ручного ввода, ноman 3 regex
дает вам страницу, объясняющую функции POSIX для сопоставления с образцом.Те же функции описаны в библиотеке GNU C: сопоставление регулярных выражений , в которой объясняется, что библиотека GNU C поддерживает как интерфейс POSIX.2, так и интерфейс, который библиотека GNU C имела в течение многих лет.
Например, для гипотетической программы, которая печатает, какая из строк, переданных в качестве аргумента, соответствует шаблону, переданному в качестве первого аргумента, вы можете использовать код, подобный следующему.
Последний аргумент
regcomp()
должно быть по крайней мереREG_EXTENDED
, или функции будут использовать основные регулярные выражения , что означает , что (например), нужно будет использоватьa\{3\}
вместоa{3}
использовать из расширенных регулярных выражений , которые, вероятно , что вы собираетесь использовать.POSIX.2 также имеет другую функцию группового символа соответствия:
fnmatch()
. Он не позволяет скомпилировать регулярное выражение или получить подстроки, соответствующие подвыражению, но он очень специфичен для проверки соответствия имени файла подстановочному знаку (например, он используетFNM_PATHNAME
флаг).источник
Это пример использования REG_EXTENDED. Это регулярное выражение
Позволяет ловить десятичные числа в испанской и международной системе. :)
источник
Хотя приведенный выше ответ хороший, я рекомендую использовать PCRE2 . Это означает, что вы можете буквально использовать все примеры регулярных выражений, и вам не нужно переводить их с какого-то древнего регулярного выражения.
Я уже ответил на это, но думаю, что и здесь это может помочь.
Regex In C для поиска номеров кредитных карт
Установите PCRE, используя:
Компиляция с использованием:
Проверьте мой ответ для более подробной информации.
источник