最初步的正则表达式引擎:在上个版本的基础上增加了转义字符

默认为转义字符的优先级最高,而且转义字符的作用是让输入处理函数把转义字符的下一个字符当作字符值看待,而不是可能的操作符。

当前版本并不支持c语言中那些特殊含义的转义字符,例如\t。这个特性将会在之后的版本中加上。

而对于c语言中的三元组转义字符,我将不会考虑他的存在,没啥意义。

下面是代码,欢迎测试。

  1 #include <stdio.h>
  2 #include <malloc.h>
  3 #include <string.h>
  4 //这个版本允许定义正则子表达式,定义的时候以名字开头,然后是冒号,然后是正则表达式主体。
  5 //在引用子表达式的时候,需要用中括号把子表达式括起来,因此中括号也跟其他操作符一样,作为保留字符
  6 //这个版本加入转义字符 ,即'\',但是目前的实现中只是将斜杠后面的单个字符输出,而并不考虑在c语言中特定
  7 //的转义字符的特殊含义,将来的版本将加入这些特殊含义,但是不会去考虑兼容三元组的转义字符
  8 int token[100];
  9 int token_pointer;
 10 char reg_operator[100];
 11 int reg_operator_pointer=0;
 12 int name_number=0;
 13 //注意这里name_number是全局的,而其他的几个栈及变量都是每个子表达式都复用的
 14 //其实那些变量及栈可以每次申请一个,为了节省空间,我就懒得管了,直接复用。
 15 int input_pointer=0;
 16 char reg_input[40];//由于命名表达式的存在,考虑加长字符,其实随便多大都可以处理。
 17 enum reg_opera_type
 18 {
 19     parenthesis=1,
 20     kleen,
 21     cat,
 22     or,
 23     alias,
 24     literal_char//单字符
 25 };//正则节点类型 
 26 typedef struct _reg_pattern
 27 {
 28     enum reg_opera_type type;
 29     union
 30     {
 31         struct//对应二元操作符
 32         {
 33             int left;
 34             int right;
 35         };
 36         struct//对应假名
 37         {
 38             int origin_number;
 39             int hash_table_number;
 40         };
 41         char value;//对应字符值
 42         int sub;//对应闭包运算符和括号运算符
 43     };
 44 }reg_pattern;//差不多当作抽象语法树吧 
 45 reg_pattern reg_pattern_table[100];
 46 //当前的hash只使用加法hash加上一个模97,因为考虑到97是质数
 47 typedef struct _hash_table//hash表类型 
 48 {
 49     enum _state
 50     {
 51         empty=0,
 52         in_use,
 53         deleted
 54     }state;
 55     char* name_of_alias;
 56     int reg_pattern_number;
 57 }hash_table;
 58 hash_table simple_hash_table[100];
 59 int look_up_hash_table(char* source)//查询一个名字是否在hash表中
 60 {
 61     int string_length;
 62     int counter;
 63     int index;
 64     int result;
 65     string_length=strlen(source);
 66     result=0;
 67     for(index=0;index<string_length;index++)
 68     {
 69         result+=*(source+index);
 70     }
 71     result=result%97;
 72     counter=0;
 73     while(counter<97)//顶多查询97次,如果查询达到了97次,则说明当前hash表中不存在这个字符串
 74     {
 75         if(simple_hash_table[result].state==empty)//如果当前位置为空,说明不存在这个节点,直接返回-1
 76         {
 77             return -1;
 78         }
 79         else
 80         {
 81             if(simple_hash_table[result].state==deleted)//如果为删除状态,则继续向下寻找,注意索引溢出的处理
 82             {
 83                 result=(result+1)%97;
 84                 counter++;
 85             }
 86             else
 87             {
 88                 if(strcmp(source,simple_hash_table[result].name_of_alias)==0)//如果出于使用状态,则开始比较
 89                 {
 90                     return result;//名字相同则返回索引
 91                 }
 92                 else//不同则继续向下寻找
 93                 {
 94                     result+=(result+1)%97;
 95                     counter++;
 96                 }
 97             }
 98         }
 99     }
100     return -1;//如果找了达到了97次,则返回-1
101 }
102 
103 
104 
105 
106 int insert_hash_table(char* source,int index_of_reg_pattern)
107 {
108     int string_length;
109     int counter;
110     int index;
111     int result;
112     string_length=strlen(source);
113     result=0;
114     for(index=0;index<string_length;index++)
115     {
116         result+=*(source+index);
117     }
118     result=result%97;
119     counter=0;
120     while(counter<97)
121     {
122         if(simple_hash_table[result].state==in_use)//如果在使用中,则继续下次寻找 
123         {
124             result=(result+1)%97;
125             counter++;
126         }
127         else//如果可用,则使用 
128         {
129             simple_hash_table[result].state=in_use;
130             simple_hash_table[result].name_of_alias=source;
131             simple_hash_table[result].reg_pattern_number=index_of_reg_pattern;
132             return result;
133         }
134     }
135     return -1;//已经满了 ,插入失败 
136 }
137 
138 int is_begin_of_token()
139 //判断输入字符是否可以当作一个token的开始符号,这样是为了处理非显示的连接符
140 //由于转义字符也是可以当作token的开始字符,所以也是返回1
141 {
142     switch(reg_input[input_pointer])
143     {
144     case '*':
145     case '|':
146     case '.':
147     case ']':
148     case ')':
149     case '\0':
150          return 0;
151     default: 
152         return 1;
153     }
154     //这里两个闭括号的存在都是为了处理非显示的连接符
155     //而把开括号移动到外部的switch之中
156     //主要是为了防止括号嵌套引起的错误
157 }
158 tackle_invisible_cat()//如果后面跟的是开括号(包括普通括号和假名括号)或者字符,则这时候要去处理隐式连接符
159 {
160     if(is_begin_of_token())
161     {
162         tackle_cat();
163     }
164 
165 }
166     
167 void tackle_or()//处理并操作符,这个处理完之后,输入指针也会后移
168 {
169     if(reg_operator_pointer!=0)//如果操作符栈中已经有操作符了
170     {
171         if(reg_operator[reg_operator_pointer-1]!='(')//括号另外说
172         {
173             name_number++;
174             if(reg_operator[reg_operator_pointer-1]=='.')
175                 //如果前面的优先级比当前的高,则处理前面的优先级
176             {
177                 printf("name%d is concat of name%d and name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
178             }
179             else
180                 //这里处理的是相同优先级的情况,其实这里可以与前面的合并的,只不过打印信息不同
181             {
182                 printf("name%d is  name%d or name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
183             }
184             token[token_pointer-2]=name_number;
185             token_pointer--;
186             reg_operator[reg_operator_pointer-1]='|';
187             input_pointer++;
188         }
189         else//对于括号,则直接入栈
190         {
191             reg_operator[reg_operator_pointer++]='|';
192             input_pointer++;
193         }
194     }
195     else//对于空操作符栈,也是直接入栈
196     {
197         reg_operator[reg_operator_pointer++]='|';
198         input_pointer++;
199     }
200 }
201 int tackle_cat()//处理连接符,处理完之后输入指针不会移动,因为指针本来就指向了后面的字符
202 {
203     if(reg_operator_pointer!=0)//如果操作符栈不为空
204     {
205         if(reg_operator[reg_operator_pointer-1]=='(')//如果前面有括号,则直接入栈
206         {
207             reg_operator[reg_operator_pointer++]='.';
208         }
209         else//对于前面不是括号的情况下
210         {
211             if(reg_operator[reg_operator_pointer-1]=='.')//优先级相同则输出前面的那个
212             {
213                 name_number++;
214                 printf("name%d is the concat of name%d and name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
215                 reg_pattern_table[name_number].type=cat;
216                 reg_pattern_table[name_number].left=token[token_pointer-2];
217                 reg_pattern_table[name_number].right=token[token_pointer-1];
218                 token[token_pointer-1]=0;
219                 token[token_pointer-2]=name_number;
220                 token_pointer--;
221             }
222             else//否则的话,前面的优先级比当前优先级低,操作符入栈
223             {
224                 reg_operator[reg_operator_pointer++]='.';
225             }
226         }
227     }
228     else//如果操作符栈为空,则入栈
229     {
230         reg_operator[reg_operator_pointer++]='.';
231     }
232 }
233 void tackle_parenthesis(void)//处理闭括号模式,这里有点复杂,这里匹配完之后,指针会向后移一位
234 {
235     if(reg_operator[reg_operator_pointer-1]=='(')//如果前面那个操作符为开括号,则匹配输出,并把输入指针向后移
236     {
237         name_number++;
238         printf("name%d is (name%d)\n",name_number,token[token_pointer-1]);
239         reg_pattern_table[name_number].type=parenthesis;
240         reg_pattern_table[name_number].sub=token[token_pointer-1];
241         token[token_pointer-1]=name_number;
242         input_pointer++;
243         reg_operator[--reg_operator_pointer]='\0';
244         //这时候需要考虑后面的是否少了显示的连接符,如果判断缺少连接符,则需要加上去
245         tackle_invisible_cat();
246     }
247     else//如果闭括号前面还有运算符,那么根据他们的优先级输出,这个时候输入指针是不变的,注意
248     {
249         name_number++;
250         if(reg_operator[reg_operator_pointer-1]=='.')
251         {
252             printf("name%d is the concat of name%d and name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
253             reg_pattern_table[name_number].type=cat;
254             reg_pattern_table[name_number].left=token[token_pointer-2];
255             reg_pattern_table[name_number].right=token[token_pointer-1];
256         }
257         else
258         {
259             printf("name%d is  name%d or name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
260             reg_pattern_table[name_number].type=or;
261             reg_pattern_table[name_number].left=token[token_pointer-2];
262             reg_pattern_table[name_number].right=token[token_pointer-1];
263         }
264         token[token_pointer-1]=0;
265         token[token_pointer-2]=name_number;
266         token_pointer--;
267         reg_operator_pointer--;
268     }
269 }
270 int tackle_alias(void)//注意这里处理完中括号匹配之后,还需要处理可能存在的非显示连接符
271 {

272     int length,index;
273     char* new_alias;
274     index=length=0;
275     while(reg_input[input_pointer+length]!=']')
276     {
277         length++;
278     }
279     new_alias=malloc(sizeof(char)*(length));//总的长度为length-1,另外加上一个\0。
280     for(index=0;index<length-1;index++)
281     {
282         new_alias[index]=reg_input[input_pointer+index+1];
283     }
284     new_alias[index]='\0';
285     input_pointer+=length+1;
286     index=look_up_hash_table(new_alias);//寻找hash表
287     if(index!=-1)
288     {
289         length=simple_hash_table[index].reg_pattern_number;//找到别名所代表的正则模式
290         token[token_pointer++]=length;//别名的正则模式的名字入栈
291         printf("match a alias,%s is the alias of name%d\n",new_alias,length);
292         tackle_invisible_cat();
293         return 1;
294     }
295     else//否则,返回错误信息
296     {
297         printf("the alias can't be matched\n");
298         return -1;
299     }
300 }
301 
302 int tackle_inter_reg(void)
303 {
304     token_pointer=0;
305     while(reg_input[input_pointer]!='\0')//还没处理到输入的末尾
306     {
307         switch(reg_input[input_pointer])
308         {
309         case '\\'://注意这里因为在c语言中这个字符也是转义字符,所以要双斜杠才能写出来
310             input_pointer++;
311             name_number++;
312             printf("transition literal is encounted\n");
313             printf("the literal is %c\n",reg_input[input_pointer]);
314             printf("the literal's token name is name%d\n",name_number);
315             token[token_pointer++]=name_number;
316             reg_pattern_table[name_number].type=literal_char;
317             reg_pattern_table[name_number].value=reg_input[input_pointer];
318             input_pointer++;
319             tackle_invisible_cat();
320             break;
321         case '('://对于括号,直接入栈
322             reg_operator[reg_operator_pointer++]='(';
323             input_pointer++;
324             break;
325         case ')':
326             tackle_parenthesis();
327             break;
328         case '*'://由于这个运算符优先级很高,不需要入栈了,直接拿顶上的token输出就行
329             name_number++;
330             printf("name%d is multiple of name%d\n",name_number,token[token_pointer-1]);
331             reg_pattern_table[name_number].type=kleen;
332             reg_pattern_table[name_number].sub=token[token_pointer-1];
333             token[token_pointer-1]=name_number;
334             input_pointer++;
335             tackle_invisible_cat();
336             break;
337         case '['://对于开的中括号,因为中括号中只能允许假名存在,所以直接调用函数处理,
338                 //处理完之后指针位于闭中括号的后面一个字符,所以switch中不需要考虑闭中括号了
339                 //注意处理时后面可能接上一个非显示的连接符
340                 //这个时候需要特殊处理
341             tackle_alias();
342             break;
343         case '|'://对于这个符号,
344             tackle_or();
345             break;
346         default: 
347             name_number++;
348             printf("name%d is %c\n",name_number,reg_input[input_pointer]);
349             token[token_pointer++]=name_number;
350             reg_pattern_table[name_number].type=literal_char;
351             reg_pattern_table[name_number].value=reg_input[input_pointer];
352             input_pointer++;
353             tackle_invisible_cat();
354             break;
355         }
356     }
357     //处理完了输入,这个时候可能还有剩余的内容在栈中
358     while(reg_operator_pointer>=1)//如果全部的输入都弄完了,可是 操作符栈中还有数据,则输出 
359     {
360         name_number++;
361         if(reg_operator[reg_operator_pointer-1]=='.')
362         {
363             printf("name%d is concat of name%d and name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);    
364             reg_pattern_table[name_number].type=cat;
365             reg_pattern_table[name_number].left=token[token_pointer-2];
366             reg_pattern_table[name_number].right=token[token_pointer-1];
367 
368         }
369         else
370         {
371             printf("name%d is name%d or name%d\n",name_number,token[token_pointer-2],token[token_pointer-1]);
372             reg_pattern_table[name_number].type=or;
373             reg_pattern_table[name_number].left=token[token_pointer-2];
374             reg_pattern_table[name_number].right=token[token_pointer-1];
375 
376         }
377         token[token_pointer-2]=name_number;
378         token_pointer--;
379         reg_operator_pointer--;
380     }
381     return name_number;//返回最后一个生成的token,作为假名的正则代号
382 }
383 int tackle_particle()//这里处理一个正则表达式名字的定义,每次处理完之后复用输入数组
384 {
385     //首先处理假名部分
386     int index;
387     char* name;
388     input_pointer=0;
389     while(reg_input[input_pointer++]!=':')//注意这里在停止迭代之后,指针指的是冒号后面的那个字符,
390     {
391         //一直向后找,直到找到冒号分隔符
392     }
393     //字符串长度比指针的值小1
394     name=malloc(sizeof(char)*(input_pointer));//考虑到字符串的结尾\0,于是不需要减1了
395     for(index=0;index<input_pointer-1;index++)//把名字复制过去
396     {
397         name[index]=reg_input[index];
398     }
399     name[index]='\0';
400     index=tackle_inter_reg();//处理当前的小正则表达式,并得到这个表达式所生成的名字
401     insert_hash_table(name,index);
402     printf("creat a alias: %s is name%d\n",name,index);//输出,建立了一个新的假名
403 }
404 
405 int main(void)
406 {
407     int index;
408     printf("please type in your short regex definition\n");
409     printf("if there is no more definition, just enter a newline\n");
410     while(scanf("%s",reg_input))
411     {
412         tackle_particle();
413         printf("please type in your short regex definition\n");
414         printf("if there is no more definition, just enter a newline\n");
415     }
416     for(index=0;index<97;index++)
417     {
418         if(simple_hash_table[index].state==in_use)
419         {
420             printf("there is a alias whose name is %s\n",simple_hash_table[index].name_of_alias);
421             free(simple_hash_table[index].name_of_alias);
422         }
423     }
424 }

 

posted @ 2013-06-23 13:07  huangnima  阅读(352)  评论(0编辑  收藏  举报