Регулярные выражения в примерах C:?

Я после нескольких простых примеров и лучших практик использования регулярных выражений в ANSI C. man regex.h не предоставляет такой большой помощи.

Ответ 1

Регулярные выражения на самом деле не являются частью ANSI C. Похоже, вы можете говорить о библиотеке регулярных выражений POSIX, которая поставляется с большинством (всего?) * nixes. Здесь пример использования POSIX-регексов в C (на основе this):

#include <regex.h>        
regex_t regex;
int reti;
char msgbuf[100];

/* Compile regular expression */
reti = regcomp(&regex, "^a[[:alnum:]]", 0);
if (reti) {
    fprintf(stderr, "Could not compile regex\n");
    exit(1);
}

/* Execute regular expression */
reti = regexec(&regex, "abc", 0, NULL, 0);
if (!reti) {
    puts("Match");
}
else if (reti == REG_NOMATCH) {
    puts("No match");
}
else {
    regerror(reti, &regex, msgbuf, sizeof(msgbuf));
    fprintf(stderr, "Regex match failed: %s\n", msgbuf);
    exit(1);
}

/* Free memory allocated to the pattern buffer by regcomp() */
regfree(&regex);

В качестве альтернативы вы можете проверить PCRE, библиотеку для совместимых с Perl регулярных выражений в C. Синтаксис Perl довольно это тот же синтаксис, используемый в Java, Python и ряде других языков. Синтаксис POSIX - это синтаксис, используемый grep, sed, vi и т.д.

Ответ 2

Вероятно, это не то, что вы хотите, но инструмент, например re2c, может скомпилировать POSIX (-ish) регулярные выражения для ANSI C. Он написан как замена для lex, но этот подход позволяет вам жертвовать гибкостью и удобочитаемостью для последнего бит скорости, если вам это действительно нужно.

Ответ 3

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 (&regex, 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 (&regex, 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, &regex, NULL, 0);
          print_regerror (result, length, &regex);       
          return EXIT_FAILURE;
        }
    }

  /* Free the memory allocated from regcomp(). */
  regfree (&regex);
  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).