Reguläre Ausdrücke in C: Beispiele?

Lesezeit: 9 Minuten

Benutzeravatar von Dervin Thunk
Dervin Thunk

Ich bin auf der Suche nach einigen einfachen Beispielen und Best Practices zur Verwendung regulärer Ausdrücke in ANSI C. man regex.h bietet nicht so viel Hilfe.

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

    – Jo

    6. Juli 2009 um 1:59 Uhr

  • Rob Pike schrieb eine kleine Suchfunktion für reguläre Ausdrücke, die eine sehr nützliche Teilmenge regulärer Ausdrücke für das Buch The Practice of Programming akzeptierte, das er und Brian Kernighan Mitautor. Siehe diese Diskussion, A Regular Expression Matcher, von Dr. Kernighan cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html

    – Richard Kammern

    14. Dezember 2014 um 23:18 Uhr


Benutzeravatar von Laurence Gonsalves
Laurence Gonsalve

Reguläre Ausdrücke sind eigentlich kein Teil von ANSI C. Es klingt, als würden 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 von POSIX-Regexes in C (basierend auf Dies):

#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 können Sie auch auschecken PCRE, eine Bibliothek für Perl-kompatible reguläre Ausdrücke in C. Die Perl-Syntax ist im Wesentlichen die gleiche Syntax, die in Java, Python und einer Reihe anderer Sprachen verwendet wird. Die POSIX-Syntax ist die von verwendete Syntax grep, sed, vietc.

  • Sofern Sie nicht die Abhängigkeit von PCRE vermeiden müssen, hat es einige nette Syntaxverbesserungen und ist sehr stabil. Zumindest bei einigen älteren Versionen von Linux ist es nicht allzu schwierig, die „eingebaute“ Bibliothek für reguläre Ausdrücke zum Absturz zu bringen, wenn bestimmte Eingabezeichenfolgen und bestimmte reguläre Ausdrücke gegeben sind, die „fast“ übereinstimmen oder viele Sonderzeichen enthalten

    – bdk

    6. Juli 2009 um 2:16 Uhr

  • @Laurence Was bedeutet es, 0 an regcomp zu übergeben? regcomp benötigt nur vier ganzzahlige Werte 1, 2, 4 und 8, um 4 verschiedene Modi darzustellen.

    – Lixiang

    21. September 2013 um 7:40 Uhr


  • @lixiang Der letzte Parameter von regcomp, cflags, ist eine Bitmaske. Aus pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html : “Das cflags-Argument ist das bitweise inklusive OR von null oder mehr der folgenden Flags…”. Wenn Sie null ODER-verknüpfen, erhalten Sie 0. Ich sehe das auf der Linux-Manpage für regcomp sagt “cflags kann das bitweise Oder von einem oder mehreren der folgenden sein”, was irreführend erscheint.

    – Laurence Gonsalves

    22. September 2013 um 18:11 Uhr

  • Sie können Text aus übereinstimmenden Gruppen mit etwas wie: 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); } Beachten Sie, dass Gruppenübereinstimmungen bei 1 beginnen, Gruppe 0 ist die gesamte Zeichenfolge. Fügen Sie Fehlerprüfungen für Out-of-Bounds usw. hinzu.

    – BurnsBA

    7. Februar 2016 um 7:42 Uhr


  • Über ob regfree ist nach einem Fehlschlag erforderlich regcompobwohl es wirklich ziemlich unterspezifiziert ist, deutet dies darauf hin, dass es nicht getan werden sollte: redhat.com/archives/libvir-list/2013-September/msg00276.html

    – Daniel Jour

    17. Juni 2016 um 19:50 Uhr

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

Benutzeravatar von Diego Campos
Diego Campos

Dies ist ein Beispiel für die Verwendung von REG_EXTENDED. Dieser reguläre Ausdruck

"^(-)?([0-9]+)((,|.)([0-9]+))?\n$"

Ermöglicht das Erfassen von Dezimalzahlen im spanischen und internationalen System. 🙂

#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(&regex, "^(-)?([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(&regex, msgbuf, 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);
    }

}

  • denkst du nicht, es ist besser zu behalten regcomp außerhalb der Schleife?. es sei denn, es sollte jedes Mal initialisiert werden, wenn es verwendet wird.

    – milevyo

    6. August 2021 um 20:08 Uhr


Benutzeravatar von apaderno
apaderno

man regex.h zeigt keinen manuellen Eintrag für regex.h, aber man 3 regex zeigt eine Seite, die die POSIX-Funktionen für den Mustervergleich erklärt.
Die gleichen Funktionen sind in beschrieben Die GNU C-Bibliothek: Abgleich regulärer Ausdrückewas erklärt, dass die GNU-C-Bibliothek sowohl die POSIX.2-Schnittstelle als auch die Schnittstelle unterstützt, die die GNU-C-Bibliothek seit vielen Jahren hat.

Beispielsweise könnten Sie für ein hypothetisches Programm, das ausgibt, welche der als Argument übergebenen Zeichenfolgen mit dem als erstes Argument übergebenen Muster übereinstimmen, einen ähnlichen Code wie den folgenden 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 sein REG_EXTENDEDoder die Funktionen werden verwendet grundlegende reguläre Ausdrückewas bedeutet, dass Sie (zum Beispiel) verwenden müssten a\{3\} Anstatt von a{3} benutzt von Erweiterte reguläre Ausdrückewas Sie wahrscheinlich verwenden möchten.

POSIX.2 hat auch eine andere Funktion für Wildcard-Matching: fnmatch(). Es erlaubt nicht, den regulären Ausdruck zu kompilieren oder die Teilzeichenfolgen zu erhalten, die mit einem Teilausdruck übereinstimmen, aber es ist sehr spezifisch, um zu prüfen, ob ein Dateiname mit einem Platzhalter übereinstimmt (z. B. verwendet es die FNM_PATHNAME Flagge).

Der Benutzeravatar von LUser
LBenutzer

Obwohl die obige Antwort gut ist, empfehle ich die Verwendung PCRE2. Das bedeutet, dass Sie jetzt buchstäblich alle Regex-Beispiele verwenden können und nicht von irgendeiner alten Regex übersetzen müssen.

Ich habe bereits eine Antwort darauf gegeben, aber ich denke, es kann auch hier helfen.

Regex in C, um nach Kreditkartennummern zu suchen

// 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;

}

Installieren Sie PCRE mit:

wget https://ftp.pcre.org/pub/pcre/pcre2-10.31.zip
make 
sudo make install 
sudo ldconfig

Kompilieren mit:

gcc foo.c -lpcre2-8 -o foo

Überprüfen Sie meine Antwort für weitere Details.

1425660cookie-checkReguläre Ausdrücke in C: Beispiele?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy