2009-07-05 7 views
127

Ich bin nach einigen einfachen Beispielen und Best Practices für die Verwendung regulärer Ausdrücke in ANSI C. man regex.h bietet nicht so viel Hilfe.Reguläre Ausdrücke in C: Beispiele?

+5

Es gibt keine integrierte Unterstützung für Regex in ANSI C. Welche Regex-Bibliothek verwenden Sie? – Joe

+5

[Rob Pike] (http://en.wikipedia.org/wiki/Rob_Pike) schrieb eine kleine reguläre Ausdruck-String-Suchfunktion, die eine sehr nützliche Teilmenge von regulären Ausdrücken für das Buch The Practice of Programming akzeptierte, das er und [Brian Kernighan ] (http://en.wikipedia.org/wiki/Brian_Kernighan) Mitautor. Siehe diese Diskussion, ein Regular Expression Matcher, von Dr. Kernighan http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html –

Antwort

167

Reguläre Ausdrücke sind eigentlich nicht Teil von ANSI C. Es klingt, als ob Sie über die POSIX-Bibliothek für reguläre Ausdrücke sprechen, die mit den meisten (allen?) * Nixen geliefert wird. Hier ist ein Beispiel für die Verwendung POSIX reguläre Ausdrücke in C (basierend auf 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); 

Alternativ Sie können PCRE überprüfen, eine Bibliothek für Perl-kompatible reguläre Ausdrücke in C. Der Perl-Syntax so ziemlich, dass dieselbe Syntax wie in Java, Python und einer Reihe anderer Sprachen. Die POSIX-Syntax wird die Syntax von grep, sed, vi usw. verwendet

+4

Wenn Sie die Abhängigkeit nicht vermeiden müssen, ich zweite PCRE, hat es einige nette Syntaxverbesserungen und ist sehr stabil. Zumindest mit einigen älteren Versionen von Linux ist die "eingebaute" Bibliothek für reguläre Ausdrücke nicht zu schwer zum Absturz zu bringen, wenn bestimmte Eingabezeichenfolgen und bestimmte reguläre Ausdrücke "fast" übereinstimmen oder viele Sonderzeichen enthalten. – bdk

+0

@Laurence Was ist die Bedeutung? von 0 an regcomp übergeben? regcomp benötigt nur vier ganzzahlige Werte 1, 2, 4 und 8, um 4 verschiedene Modi darzustellen. – lixiang

+2

@lixiang Der letzte Parameter zu 'regcomp',' cflags', ist eine Bitmaske. Von http://pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html: "Das Argument cflags ist das bitweise inklusive ODER von null oder mehr der folgenden Flags ...". Wenn Sie ODER-zusammen Null, erhalten Sie 0. Ich sehe, dass die Linux-Manpage für 'regcomp" sagt "cflags kann die bitweise sein-oder von einem oder mehreren der folgenden", die irreführend scheint. –

9

Es ist wahrscheinlich nicht das, was Sie wollen, aber ein Tool wie re2c kann POSIX (ish) reguläre Ausdrücke ANSI C kompilieren Es ist als Ersatz geschrieben für lex, aber dieser Ansatz ermöglicht es Ihnen, Flexibilität und Lesbarkeit für das letzte bisschen Geschwindigkeit zu opfern, wenn Sie es wirklich brauchen.

3

man regex.h Berichte Es gibt keinen manuellen Eintrag für regex.h, aber man 3 regex gibt Ihnen eine Seite, auf der die POSIX-Funktionen für die Mustererkennung erläutert werden.

Die gleichen Funktionen sind in The GNU C Library: Regular Expression Matching beschrieben, wo erklärt wird, dass die GNU C-Bibliothek sowohl die POSIX.2-Schnittstelle unterstützt, als auch die, die die GNU C-Bibliothek seit vielen Jahren hat.

Zum Beispiel für eine hypothetische Programm, das Drucken, die von den als Argument übergeben Strings übereinstimmen das Muster als erstes Argument übergeben, Sie Code ähnlich dem folgenden ein verwenden:

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

Das letzte Argument von regcomp() muss mindestens REG_EXTENDED sein, oder die Funktionen werden basic regular expressions verwenden, was bedeutet, dass Sie zum Beispiel a\{3\} anstelle von a{3} aus extended regular expressions verwenden müssten, was wahrscheinlich zu erwarten ist.

POSIX.2 hat auch eine andere Funktion für den Wildcard-Abgleich: fnmatch(). Es ist nicht möglich, den regulären Ausdruck zu kompilieren oder die Teilzeichenfolgen mit einem Unterausdruck abzugleichen, aber es ist sehr spezifisch für die Überprüfung, wenn ein Dateiname einem Platzhalter entspricht (z. B. verwendet er das FNM_PATHNAME Flag).