首页 > 代码库 > pcre库编写的正则匹配程序

pcre库编写的正则匹配程序

使用的是Philip Hazel的Perl-Compatible Regular Expression库,参考:

http://see.xidian.edu.cn/cpp/html/1428.html

执行匹配的时:

gcc myreg.c

ip.pat 内容:

 ip
.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

ip.txt 内容:

192.168.1.1

测试:

./a.out ip.pat ip.txt

下面是myreg.c源代码

/*  myreg.c  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <regex.h>
#include <unistd.h>


#define MAX 256

/* 存放匹配位置信息的结构体 */
typedef struct placemsg_t
{
 int start[MAX]; //匹配的开始位置
 int end[MAX];   //匹配的结束位置
 int count;      //匹配次数
} placemsg;

#define TIMES 100
#define MAX_PATTERN_LEN 8192

/**
 * @brief 实现一个字符十六进制到十进制的转换
 *
 * @param c 需要转换的字符
 *
 * @return 错误返回 -1
 */
static int hex2dec(char c)
{
        switch (c)
        {
                case ‘0‘ ... ‘9‘:
                        return c - ‘0‘;
                case ‘a‘ ... ‘f‘:
                        return c - ‘a‘ + 10;
                case ‘A‘ ... ‘F‘:
                        return c - ‘A‘ + 10;
                default:
   fprintf(stderr, "hex2dec: bad value!\n");
            return -1;          
        }
}

/*
 * @brief  把正则的\xHH格式的十六进制形式用字符形式代替
 * takes a string with \xHH escapes and returns one with the characters they stand for
 *
 * @param s \xHH形式的正则表达式
 *
 * @return  返回字符形式的正则表达式
 */
static char *pre_process(char *s)
{
        char *result = malloc(strlen(s) + 1);
        int sindex = 0, rindex = 0;
        while( sindex < strlen(s) ) 
        {
            if( sindex + 3 < strlen(s) &&
                s[sindex] == ‘\\‘ && s[sindex+1] == ‘x‘ &&
                isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) )
                {
                        /* carefully remember to call tolower here... */
                        result[rindex] = tolower( hex2dec(s[sindex + 2])*16 +
                                                  hex2dec(s[sindex + 3] ) );
                        sindex += 3; /* 4 total */
                }
                else
                        result[rindex] = tolower(s[sindex]);

                sindex++; 
                rindex++;
        }
        result[rindex] = ‘\0‘;

        return result;
}

 

//判断是不是注释
// Returns true if the line (from a pattern file) is a comment
static int is_comment(char* line)
{
 unsigned int i;
    // blank lines are comments
    if(strlen(line) == 0) return 1;

    // lines starting with # are comments
    if(line[0] == ‘#‘) return 1;

    // lines with only whitespace are comments
    for(i = 0; i < strlen(line); i++)
 {
       if(!isspace(line[i]))
    {
   return 0;
    }
 }
    return 1;
}

//获得.pat中的协议名称
static char *get_protocol_name (char *line, char **patname)
{
 unsigned int i, j;
 char *name = *patname;
 j = 0;
 for (i=0; i<strlen(line); i++)
 {
  if(!isspace (line[i]))
  {
   name[j] = line[i];
   j++;
  }
  else
  {
   break;
  }
 }
 return name;
}

//找到最后的slash(/)
int last_mark (char *str, char mark)
{
 int site = 0;  
 int count = 0;
 int size = strlen(str);
 while (site <= size)
 {
  if (str[site++] == mark)
  {
   count = site; 
  }
 }
 return count;
}

//找到第一个dot(.)
int first_mark (char *str, char mark, int num)
{
 int count = num;
 while (1)  
 {
  if (str[count++] == mark)
  {
   break;
  }
 }
 return count; 
}

/* 从文件全名中把文件名提取出来,没有后缀 */
int substr (char *srcstr, char **decstr, int lastslash, int firstdot)
{
 int i = 0;
 //int ls = lastslash;
 char *str = *decstr;
 //printf("last=%d,first=%d\n", lastslash, firstdot);
 //printf("size=%d\n", firstdot-lastslash);
 int size = firstdot-lastslash-1;
 for (i=0; i<size; i++)
 {
  //str[i] = srcstr[ls++];
  //printf("...%c...\n",srcstr[lastslash]);
  str[i] = srcstr[lastslash++];
 }
}

//得到文件名
int basename(char *file, char **name)
{
 int lastnum = last_mark (file, ‘/‘);
 int firstnum = first_mark (file, ‘.‘, lastnum);
 substr (file, name, lastnum, firstnum);
 //printf ("name = %s\n", name);

 return 0;
}

 

/**
 * @brief 以下是pcre匹配的相关函数原型:
 *   int regcomp(regex_t *preg, const char *regex, int cflags);
 *   cflags: REG_EXTENDED | REG_NEWLINE;
 *     REG_EXTENDED  支持扩展的正则
 *     REG_NEWLINE;  包括换行
 *      int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
 *   eflags = REG_NOTBOL | REG_NOTEOL;
 *      REG_NOTBOL  行结尾
 *      REG_NOTEOL  文件结尾
 *          size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
 *          void regfree(regex_t *preg);
 * @param regexp 正则表达式模式文件
 * @param file_path 要进行匹配的文件路径
 *
 * @return  匹配信息结构体
 */
struct placemsg_t reg(char *regexpfile, char *file_path)
{
  regex_t preg;
  struct placemsg_t placeinfo;

  regmatch_t pmatch[MAX] = {};
  size_t nmatch = MAX;
  size_t length;
  char errbuf[MAX] = {};
  size_t errbuf_size;
  int res;
  int errcode;

  FILE *fp;
  int fd;
  long sitestart;
  long siteend;
  long filesize;
  char *string;


  int patternlen, i;
  int flag = 1;
  FILE * fp2;
  char * line = NULL;
  size_t len = 0;
  ssize_t size;

  char *filename = (char*)malloc(256);
  //提取.pat文件名
  basename(regexpfile, &filename);

 //提取.pat中的正则表达式
 //printf ("1regexpfile=%s\n", regexpfile);
 fp2 = fopen (regexpfile, "r");
 if (fp2 == NULL)
 {
  perror("fopen");
 }
 flag = 1;
 while ((size= getline(&line, &len, fp2)) != -1)
 {
  line[strlen(line)-1] = ‘\0‘;
  //printf ("line=%s\n", line);
  //判断是否是注释
  if(is_comment(line))
  {
   printf("is_comment\n");
   continue;
  }
  else if((strstr(line, filename) == 0) && flag)
  {
   //printf("..........strcpy...........\n");
   flag = 0;
   continue;
  }
  else if(flag)
  {
   continue;
  }
  else if (flag == 0)
  {
   printf("正则表达式是:%s\n", line);
   break;
  }
 }
 fclose(fp2);
 fp2 = NULL;
 free(filename);
 printf ("2line=%s\n", line);

 //转换正则表达式为字符
 char *regexpstr = pre_process(line); /* do \xHH escapes */
 printf("regexpstr=%s\n", regexpstr);
 if(line)
 {
  free(line);
 }

  printf("file_path=%s\n", file_path);
  fp = fopen(file_path, "r");
  if (fp == NULL)
  {
  perror("fopen");
  }

  fseek(fp, 0, SEEK_SET);
  sitestart = ftell(fp);
  fseek(fp, 0, SEEK_END);
  siteend = ftell(fp);
  filesize = siteend - sitestart;
  printf("filezize=%d\n", filesize);
  string = (char*) malloc(sizeof(char)*filesize+4);
  memset(string, 0, filesize+4);
  fclose(fp);
  fp = NULL;

  fd = open(file_path, O_RDONLY);
  if (fd == -1)
  {
 perror ("open");
  }

  res = read(fd, string, filesize);
  if (res == -1)
  {
 perror ("read");
  }

  close(fd);
  printf("res=%d,string=%s\n", res, string);

  printf("begin regcomp.........\n");
  int cflags = REG_EXTENDED | REG_NEWLINE;
  //int cflags = REG_EXTENDED;
  //int cflags = 0;
  //编译正则表达式
  res = regcomp (&preg, regexpstr, cflags);

  printf("begin regexec.........\n");
  //int eflags = REG_NOTBOL | REG_NOTEOL;
  int eflags =  REG_NOTEOL;
  //int eflags = 0;
  int place[5];
  int start_front=0;
  int start_now=0;
  int end_front=0;
  int end_now=0;
  int temp = 0;
 
  char *p = string;
  i = 0;
  while (1)
  {
    res = regexec (&preg, p, nmatch, pmatch, eflags);
    if (res == 0)
    {
      printf("...........match..........\n");
   start_now = pmatch[0].rm_so;
   end_now = pmatch[0].rm_eo;
 
   temp = end_now - start_now;
   //printf("temp=%d\n", temp);
   start_now = end_front + start_now;
   //printf("start_now=%d\n", start_now);
      end_now = start_now + temp;
   //printf("end_now=%d\n", end_now);

   start_front = start_now;
   end_front = end_now;

   //printf("start place=%d\n", pmatch[0].rm_so);
   //printf("end place=%d\n", pmatch[0].rm_eo);
   //printf("start place=%d\n", start_front);
   //printf("end place=%d\n", end_front);
   placeinfo.start[i] = start_front;
   placeinfo.end[i] = end_front;

   p += pmatch[0].rm_eo;
   if(!*p)
   {
  i++;
  break;
   }

    }
    else
    {
   printf("no match\n");
   break;
    }

 i++;
  }
 
  placeinfo.count = i;
  //printf(".....i=%d\n", i);
  length = regerror (res, &preg, errbuf, errbuf_size);

  regfree(&preg);
  free(string);
  free(regexpstr);

  //printf("over\n");

  return placeinfo;
}

int main (int argc, char **argv)
{
 //char *regexp = "r.t";
 char *regexpfile = argv[1];
 
 printf("regexpfile=%s\n", regexpfile);
 //char *file_path = "t.txt";
 char *file_path = argv[2];

 struct placemsg_t placeinfo;

 placeinfo = reg(regexpfile, file_path);
 int size = placeinfo.count;
 printf(".....show....\n");
 int i = 0;
 for (i=0; i<size; i++)
 {
  printf ("start[%d]=%d\n", i, placeinfo.start[i]);
  printf ("end[%d]=%d\n", i, placeinfo.end[i]);
 }
 return 0;
}