2009-07-05 45 views
127

Estoy buscando algunos ejemplos simples y las mejores prácticas de cómo usar expresiones regulares en ANSI C. man regex.h no proporciona mucha ayuda.Expresiones regulares en C: ejemplos?

+5

No hay compatibilidad integrada para expresiones regulares en ANSI C. ¿Qué biblioteca de expresiones regulares está utilizando? – Joe

+5

[Rob Pike] (http://en.wikipedia.org/wiki/Rob_Pike) escribió una pequeña función de búsqueda de cadenas de expresiones regulares que aceptaba un subconjunto muy útil de expresiones regulares para el libro The Practice of Programming que él y [Brian Kernighan ] (http://en.wikipedia.org/wiki/Brian_Kernighan) coautor. Vea esta discusión, Un Expression Matcher Regular, por Dr. Kernighan http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html –

Respuesta

167

Las expresiones regulares en realidad no son parte de ANSI C. Parece que podría estar hablando de la biblioteca de expresiones regulares POSIX, que viene con la mayoría de (todos?) * Nixes. He aquí un ejemplo del uso de expresiones regulares POSIX en C (basado en 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); 

Alternativamente, es posible que desee comprobar hacia fuera PCRE, una biblioteca de expresiones regulares compatibles con Perl en la sintaxis C. El Perl es más o menos que misma sintaxis utilizada en Java, Python y varios otros lenguajes. La sintaxis POSIX es la sintaxis utilizada por grep, sed, vi, etc.

+4

A menos que necesite evitar la dependencia que tengo de PCRE por segunda vez, tiene algunas bonitas mejoras de sintaxis y es muy estable. Al menos con algunas versiones anteriores de Linux, la biblioteca de expresiones regulares "incorporadas" no es demasiado difícil de bloquear dado ciertas cadenas de entrada y ciertas expresiones regulares que "casi" coinciden o involucran muchos caracteres especiales – bdk

+0

@Laurence ¿Cuál es el significado? de pasar 0 a regcomp? regcomp solo toma cuatro valores enteros 1, 2, 4 y 8 para representar 4 modos diferentes. – lixiang

+2

@lixiang El último parámetro para 'regcomp',' cflags', es una máscara de bits. De http://pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html: "El argumento cflags es el O bit-inclusivo de cero o más de los siguientes indicadores ...". Si tu O-juntos cero, obtendrás 0. Veo que la página de manual de Linux para 'regcomp' dice" cflags puede ser bitwise-o de uno o más de los siguientes ", lo que parece engañoso. –

9

Probablemente no es lo que quiere, pero una herramienta como re2c puede compilar POSIX (ish) expresiones regulares para ANSI C. Está escrito como un reemplazo para lex, pero este enfoque le permite sacrificar flexibilidad y legibilidad para el último bit de velocidad, si realmente lo necesita.

3

man regex.h informa que no hay entrada manual para regex.h, pero man 3 regex le ofrece una página que explica las funciones POSIX para la coincidencia de patrones.

Las mismas funciones se describen en The GNU C Library: Regular Expression Matching, donde se explica que la Biblioteca GNU C es compatible tanto con la interfaz POSIX.2 como con la que la Biblioteca GNU C ha tenido durante muchos años.

Por ejemplo, para un hipotético programa que imprime cuál de las cadenas pasadas como argumento coinciden con el patrón pasa como primer argumento, se podría utilizar un código similar al siguiente:

#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); 
} 

El último argumento de regcomp() tiene que ser al menos REG_EXTENDED, o las funciones usarán basic regular expressions, lo que significa que (por ejemplo) necesitaría usar a\{3\} en lugar de usado desde extended regular expressions, que es probablemente lo que espera usar.

POSIX.2 también tiene otra función para la coincidencia de comodines: fnmatch(). No permite compilar la expresión regular u obtener las subcadenas que coincidan con una sub-expresión, pero es muy específica para verificar cuando un nombre de archivo coincide con un comodín (por ejemplo, usa el indicador FNM_PATHNAME).

Cuestiones relacionadas