【问题标题】:Regular expressions in C: examples?C中的正则表达式:示例?
【发布时间】:2010-11-08 06:38:51
【问题描述】:

我正在寻找一些关于如何在 ANSI C 中使用正则表达式的简单示例和最佳实践。man regex.h 并没有提供太多帮助。

【问题讨论】:

标签: c regex


【解决方案1】:

正则表达式实际上不是 ANSI C 的一部分。听起来您可能在谈论 POSIX 正则表达式库,它与大多数(全部?)*nixes 一起提供。这是在 C 中使用 POSIX 正则表达式的示例(基于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,这是一个用于在 C 中与 Perl 兼容的正则表达式的库。Perl 语法与 Java、Python 和许多其他语言中使用的语法几乎相同。 POSIX语法是grepsedvi等使用的语法。

【讨论】:

  • 除非你需要避免依赖我第二个PCRE,它有一些很好的语法增强并且非常稳定。至少对于一些旧版本的 Linux,“内置”正则表达式库不会太难崩溃,因为某些输入字符串和某些“几乎”匹配或涉及许多特殊字符的正则表达式
  • @Laurence 把0传给regcomp是什么意思? regcomp 只取四个整数值 1、2、4 和 8 来表示 4 种不同的模式。
  • @lixiang regcomp 的最后一个参数cflags 是位掩码。来自pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html:“cflags 参数是以下标志中的零个或多个的按位或运算...”。如果您将零加在一起,您将得到 0。我看到regcomp 的 Linux 联机帮助页说“cflags 可能是以下一项或多项的按位或”,这似乎具有误导性。
  • 您可以从匹配组中提取文本,例如:regmatch_t matches[MAX_MATCHES]; if (regexec(&amp;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); } 注意组匹配从 1 开始,组 0 是整个字符串。为越界等添加错误检查。
  • 关于在regcomp失败后是否需要regfree,虽然它确实是相当不明确的,这表明它不应该这样做:redhat.com/archives/libvir-list/2013-September/msg00276.html
【解决方案2】:

这可能不是您想要的,但是像 re2c 这样的工具可以将 POSIX(-ish) 正则表达式编译为 ANSI C。它是作为 lex 的替代品编写的,但是这种方法允许您牺牲灵活性和易读性最后一点速度,如果你真的需要的话。

【讨论】:

    【解决方案3】:

    这是使用 REG_EXTENDED 的示例。 这个正则表达式

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

    允许您捕捉西班牙系统和国际系统中的十进制数字。 :)

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

    【讨论】:

    • 你不觉得,最好把regcomp 放在循环之外?除非它应该在每次使用时都被初始化。
    【解决方案4】:

    man regex.h 报告 regex.h 没有手动输入,但man 3 regex 为您提供了一个解释用于模式匹配的 POSIX 函数的页面。
    The GNU C Library: Regular Expression Matching 中描述了相同的功能,它解释了 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,否则函数将使用basic regular expressions,这意味着(例如)您需要使用a\{3\} 而不是使用的a{3} extended regular expressions,这可能是你期望使用的。

    POSIX.2 还有另一个通配符匹配功能:fnmatch()。它不允许编译正则表达式,或获取与子表达式匹配的子字符串,但它非常适用于检查文件名何时匹配通配符(例如,它使用FNM_PATHNAME 标志)。

    【讨论】:

      【解决方案5】:

      虽然上面的答案很好,但我建议使用 PCRE2。这意味着您现在可以从字面上使用所有的正则表达式示例,而不必从一些古老的正则表达式中翻译。

      我已经对此做出了回答,但我认为它在这里也可以提供帮助..

      Regex In C To Search For Credit Card Numbers

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

      使用以下方式安装 PCRE:

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

      编译使用:

      gcc foo.c -lpcre2-8 -o foo
      

      查看我的回答了解更多详情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多