inux C 正则表达式

 下面介绍下如何使用:
    首先,编译正则表达式。
    为了提高效率,在将一个字符串与正则表达式进行比较之前,首先要用regcomp()函数对它进行编译,将其转化为regex_t结构:
   
    int regcomp(regex_t *preg, const char *regex,int cflags);
   
    参数regex是一个字符串,它代表将要被编译的正则表达式;参数preg指向一个声明为regex_t的数据结构,用来保存编译结果;参数cflags 决定了正则表达式该如何被处理的细节。(此处可以用man regcomp 命令查看详细的解释)
    如果函数regcomp()执行成功,并且编译结果被正确填充到preg中后,函数将返回0,任何其它的返回结果都代表有某种错误产生。
   
    接下来匹配正则表达式。
    一旦用regcomp()成功地编译了正则表达式,接下来就可以调用regexec()完成模式匹配:

    int regexec(const regex_t *preg, const char *string, size_t nmatch,regmatch_t pmatch[], int eflags);
    typedef struct
    {
        regoff_t rm_so;
        regoff_t rm_eo;
    } regmatch_t;   

    参数preg指向编译后的正则表达式,参数string是将要进行匹配的字符串,而参数nmatch和pmatch则用于把匹配结果返回给调用程序,最后 一个参数eflags决定了匹配的细节。

    在调用regexec()进行模式匹配的过程中,可能在字符串string中会有多处与给定的正则表达式相匹配,参数pmatch就是用来保存这些匹配位 置的,而参数nmatch则告诉regexec()最多可以把多少个匹配结果填充到pmatch数组中。当regexec()成功返回时,从 string+pmatch[0].rm_so到string+pmatch[0].rm_eo是第一个匹配的字符串,而从string+ pmatch[1].rm_so到string+pmatch[1].rm_eo,则是第二个匹配的字符串,依此类推。

    最后释放正则表达式。
    无论什么时候,当不再需要已经编译过的正则表达式时,都应该调用regfree()将其释放,以免产生内存泄漏。
    void regfree(regex_t *preg);

    报告错误信息
  
 如果调用regcomp()或regexec()得到的是一个非0的返回值,则表明在对正则表达式的处理过程中出现了某种错误,此时可以通过调用 regerror()得到详细的错误信息。

    size_t regerror(int errcode, const regex_t *preg, char *errbuf,size_t errbuf_size);

    参数errcode是来自regcomp()或regexec()的错误代码,而参数preg则是由regcomp()得到的编译结果,其目的是把格式化 消息所必须的上下文提供给regerror()。在执行regerror()时,将按照参数errbuf_size指明的最大字节数,在errbuf缓冲 区中填入格式化后的错误信息,同时返回错误信息的长度。

 

 

 

 

附:

1.int   regcomp   (regex_t   *compiled,   const   char   *pattern,   int   cflags)  
   
  这个函数把指定的规则表达式pattern编译成一种特定的数据格式compiled,这样可以使匹配更有效。函数regexec   会使用这个数据在目标文本串中进行模式匹配。执行成功返回0。  
   
  regex_t   是一个结构体数据类型,用来存放编译后的规则表达式,它的成员re_nsub   用来存储规则表达式中的子规则表达式的个数,子规则表达式就是用圆括号包起来的部分表达式。  
   
  pattern   是指向我们写好的规则表达式的指针。  
  cflags   有如下4个值或者是它们或运算(|)后的值:  
  REG_EXTENDED   以功能更加强大的扩展规则表达式的方式进行匹配。  
  REG_ICASE   匹配字母时忽略大小写。  
  REG_NOSUB   不用存储匹配后的结果。  
  REG_NEWLINE   识别换行符,这样'$'就可以从行尾开始匹配,'^'就可以从行的开头开始匹配。  
   
  2.   int   regexec   (regex_t   *compiled,   char   *string,   size_t   nmatch,   regmatch_t   matchptr   [],   int   eflags)  
   
  当我们编译好规则表达式后,就可以用regexec   匹配我们的目标文本串了,如果在编译规则表达式的时候没有指定cflags的参数为REG_NEWLINE,则默认情况下是忽略换行符的,也就是把整个文 本串当作一个字符串处理。执行成功返回0。  
   
  regmatch_t   是一个结构体数据类型,成员rm_so   存放匹配文本串在目标串中的开始位置,rm_eo   存放结束位置。通常我们以数组的形式定义一组这样的结构。因为往往我们的规则表达式中还包含子规则表达式。数组0单元存放主规则表达式位置,后边的单元依 次存放子规则表达式位置。  
   
  compiled   是已经用regcomp函数编译好的规则表达式。  
  string   是目标文本串。  
  nmatch   是regmatch_t结构体数组的长度。  
  matchptr   regmatch_t类型的结构体数组,存放匹配文本串的位置信息。  
  eflags   有两个值  
  REG_NOTBOL   按我的理解是如果指定了这个值,那么'^'就不会从我们的目标串开始匹配。总之我到现在还不是很明白这个参数的意义,   原文如下:  
  If   this   bit   is   set,   then   the   beginning-of-line   operator   doesn't   match   the   beginning   of   the   string   (presumably   because   it's   not   the   beginning   of   a   line).If   not   set,   then   the   beginning-of-line   operator   does   match   the   beginning   of   the   string.  
  REG_NOTEOL   和上边那个作用差不多,不过这个指定结束end   of   line。  
   
  3.   void   regfree   (regex_t   *compiled)  
   
  当我们使用完编译好的规则表达式后,或者要重新编译其他规则表达式的时候,我们可以用这个函数清空compiled指向的regex_t结构体的内容,请 记住,如果是重新编译的话,一定要先清空regex_t结构体。  
   
  4.   size_t   regerror   (int   errcode,   regex_t   *compiled,   char   *buffer,   size_t   length)  
   
  当执行regcomp   或者regexec   产生错误的时候,就可以调用这个函数而返回一个包含错误信息的字符串。  
   
  errcode   是由regcomp   和   regexec   函数返回的错误代号。  
  compiled   是已经用regcomp函数编译好的规则表达式,这个值可以为NULL。  
  buffer   指向用来存放错误信息的字符串的内存空间。  
  length   指明buffer的长度,如果这个错误信息的长度大于这个值,则regerror   函数会自动截断超出的字符串,但他仍然会返回完整的字符串的长度。所以我们可以用如下的方法先得到错误字符串的长度。  
  size_t   length   =   regerror   (errcode,   compiled,   NULL,   0);  

以下是一个简单的贪吃蛇程序,使用C语言编写。该程序使用ncurses库来实现游戏的图形界面,可以在Linux系统中编译和运行。 ``` #include <stdio.h> #include <stdlib.h> #include <time.h> #include <ncurses.h> #define ROWS 20 #define COLS 40 #define SNAKE_LEN 5 typedef struct { int row; int col; } point_t; enum direction {UP, DOWN, LEFT, RIGHT}; int main() { // 初始化ncurses initscr(); cbreak(); noecho(); keypad(stdscr, TRUE); curs_set(FALSE); // 初始化游戏界面 clear(); refresh(); mvprintw(0, 0, "Press any key to start..."); getch(); // 初始化随机数生成器 srand(time(NULL)); // 初始化贪吃蛇 point_t snake[SNAKE_LEN]; snake[0].row = ROWS / 2; snake[0].col = COLS / 2; for (int i = 1; i < SNAKE_LEN; i++) { snake[i].row = snake[0].row; snake[i].col = snake[0].col - i; } enum direction dir = RIGHT; int grow = 0; // 初始化食物 point_t food; food.row = rand() % ROWS; food.col = rand() % COLS; // 开始游戏循环 while (1) { // 绘制游戏界面 clear(); for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (r == snake[0].row && c == snake[0].col) { mvprintw(r, c, "H"); } else if (grow && r == snake[SNAKE_LEN-1].row && c == snake[SNAKE_LEN-1].col) { mvprintw(r, c, "O"); grow = 0; } else if (r == food.row && c == food.col) { mvprintw(r, c, "X"); } else { for (int i = 1; i < SNAKE_LEN; i++) { if (r == snake[i].row && c == snake[i].col) { mvprintw(r, c, "o"); break; } } } } } refresh(); // 处理用户输入 int ch = getch(); if (ch == KEY_UP && dir != DOWN) { dir = UP; } else if (ch == KEY_DOWN && dir != UP) { dir = DOWN; } else if (ch == KEY_LEFT && dir != RIGHT) { dir = LEFT; } else if (ch == KEY_RIGHT && dir != LEFT) { dir = RIGHT; } // 移动贪吃蛇 for (int i = SNAKE_LEN-1; i > 0; i--) { snake[i].row = snake[i-1].row; snake[i].col = snake[i-1].col; } switch (dir) { case UP: snake[0].row--; break; case DOWN: snake[0].row++; break; case LEFT: snake[0].col--; break; case RIGHT: snake[0].col++; break; } // 检查贪吃蛇是否撞墙或吃到食物 if (snake[0].row < 0 || snake[0].row >= ROWS || snake[0].col < 0 || snake[0].col >= COLS) { mvprintw(ROWS/2, COLS/2-4, "Game Over"); break; } else if (snake[0].row == food.row && snake[0].col == food.col) { grow = 1; do { food.row = rand() % ROWS; food.col = rand() % COLS; } while (food.row == snake[0].row && food.col == snake[0].col); } // 暂停一段时间,控制游戏速度 usleep(100000); } // 清理ncurses endwin(); return 0; } ``` 运行该程序,将会在终端中显示一个贪吃蛇游戏界面。玩家可以使用方向键来控制贪吃蛇的移动,吃到食物会让贪吃蛇变长,撞到墙或自己则游戏结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值