Regelmatige uitdrukkingen in C: voorbeelden?

Ik ben op zoek naar enkele eenvoudige voorbeelden en best practices van het gebruik van reguliere expressies in ANSI C. man regex.hbiedt niet zoveel hulp.


Antwoord 1, autoriteit 100%

Reguliere expressies maken eigenlijk geen deel uit van ANSI C. Het klinkt alsof je het hebt over de POSIX-bibliotheek voor reguliere expressies, die bij de meeste (alle?) *nixes wordt geleverd. Hier is een voorbeeld van het gebruik van POSIX-regexes in C (gebaseerd op dit):

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

Als alternatief kunt u PCREbekijken, een bibliotheek voor Perl-compatibele reguliere expressies in C. De Perl-syntaxis is vrijwel dezelfde syntaxis die wordt gebruikt in Java, Python en een aantal andere talen. De POSIX-syntaxis is de syntaxis die wordt gebruikt door grep, sed, vi, enz.


Antwoord 2, autoriteit 5%

Het is waarschijnlijk niet wat je wilt, maar een tool als re2ckan POSIX(-ish) compileren reguliere expressies naar ANSI C. Het is geschreven als vervanging voor lex, maar met deze aanpak kun je flexibiliteit en leesbaarheid opofferen voor het laatste beetje snelheid, als je het echt nodig hebt.


Antwoord 3, autoriteit 4%

man regex.hmeldt dat er geen handmatige invoer is voor regex.h, maar man 3 regexgeeft je een pagina met uitleg over de POSIX-functies voor patroonherkenning.

Dezelfde functies worden beschreven in The GNU C Library : Regular Expression Matching, waarin wordt uitgelegd dat de GNU C-bibliotheek zowel de POSIX.2-interface ondersteunt als de interface die de GNU C-bibliotheek al vele jaren heeft.

Voor een hypothetisch programma dat bijvoorbeeld afdrukt welke van de als argument doorgegeven strings overeenkomt met het patroon dat als eerste argument is doorgegeven, kunt u code gebruiken die lijkt op de volgende.

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

Het laatste argument van regcomp()moet minimaal REG_EXTENDEDzijn, anders gebruiken de functies basis reguliere expressies, wat betekent dat u (bijvoorbeeld) a\{3\}moet gebruiken in plaats van a{3}gebruikt van uitgebreide reguliere expressies, dat is waarschijnlijk wat u verwacht te gebruiken.

POSIX.2 heeft ook een andere functie voor het matchen van wildcards: fnmatch(). Het staat niet toe om de reguliere expressie te compileren, of om de substrings te krijgen die overeenkomen met een sub-expressie, maar het is zeer specifiek om te controleren wanneer een bestandsnaam overeenkomt met een jokerteken (het gebruikt bijvoorbeeld de vlag FNM_PATHNAME).


Antwoord 4, autoriteit 4%

Dit is een voorbeeld van het gebruik van REG_EXTENDED.
Deze reguliere expressie

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

Hiermee kunt u decimale getallen vangen in het Spaanse systeem en internationaal. 🙂

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

Antwoord 5, autoriteit 3%

Hoewel het bovenstaande antwoord goed is, raad ik aan om PCRE2te gebruiken. Dit betekent dat je letterlijk alle regex-voorbeelden kunt gebruiken die er nu zijn en niet hoeft te vertalen vanuit een oude regex.

Ik heb hier al een antwoord op gegeven, maar ik denk dat het hier ook kan helpen..

Regex In C Zoeken Voor creditcardnummers

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

Installeer PCRE met:

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

Compileren met:

gcc foo.c -lpcre2-8 -o foo

Controleer mijn antwoord voor meer details.

Other episodes