Я після кількох простих прикладів та найкращих практик використання регулярних виразів в ANSI C. man regex.h
не допомагає настільки багато.
Я після кількох простих прикладів та найкращих практик використання регулярних виразів в ANSI C. man regex.h
не допомагає настільки багато.
Відповіді:
Регулярні вирази насправді не є частиною ANSI C. Це здається, що ви можете говорити про бібліотеку регулярних виразів POSIX, яка поставляється з більшістю (усіма?) * Нікс. Ось приклад використання 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");
}
else if (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
і т.д.
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: Regular Expression Matching , яка пояснює, що Бібліотека 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]);
}
else if (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
прапор).
Це приклад використання REG_EXTENDED. Це регулярний вираз
"^(-)?([0-9]+)((,|.)([0-9]+))?\n$"
Дозволяє ловити десяткові числа в іспанській системі та міжнародних. :)
#include <regex.h>
#include <stdlib.h>
#include <stdio.h>
regex_t regex;
int reti;
char msgbuf[100];
int main(int argc, char const *argv[])
{
while(1){
fgets( msgbuf, 100, stdin );
reti = regcomp(®ex, "^(-)?([0-9]+)((,|.)([0-9]+))?\n$", REG_EXTENDED);
if (reti) {
fprintf(stderr, "Could not compile regex\n");
exit(1);
}
/* Execute regular expression */
printf("%s\n", msgbuf);
reti = regexec(®ex, msgbuf, 0, NULL, 0);
if (!reti) {
puts("Match");
}
else if (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);
}
}
Хоча відповідь вище хороша, я рекомендую використовувати PCRE2 . Це означає, що ви можете буквально використовувати всі приклади регулярних виразів там, і вам не доведеться перекладати з деяких давніх виразів.
Я вже відповів на це, але думаю, що це може допомогти і тут.
Для пошуку номерів кредитних карт Regex In C
// 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(){
bool Debug = true;
bool Found = 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);
return 1;
}
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;
return Found;
// 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. */
return Found;
}
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);
return 0;
}
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);
return Found;
}
Встановіть 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
Перевірте мою відповідь для отримання більш детальної інформації.