flex是一个词法分析器生成器,它是编译器和解释器编程人员的常用工具之一。flex的程序主要由一系列带有指令(称为动作代码)的正则表达式组成。在匹配输入时,flex会将所有的正则表达式翻译成确定性有穷自动机,这使得flex等词法分析器生成器生成的词法分析器匹配输入模式的效率非常高。当然,有人指责flex不够灵活,功能有限,很多问题都无法解决,比如Javascript、C++等语言中二义性的问题,实际上很多程序(比如Python的解释器)的词法分析器都是用的手工代码而不是flex自动生成的。这些都不在这篇文章的讨论范围内,我主要想通过对flex和手工写的C代码编译的一个词数统计程序(word counter)来非常粗略地评价一下flex匹配正则表达式的速度如何。

  测试方法:分别运行用flex生的C代码和手工C代码编译的程序,设置三种不同大小的文件,用shell的time指令来测试两个程序运行所用的时间。

  下面上源码,先是flex源码 flexwc.l:

 /*用flex实现的一个词数统计程序。
flexwc.l
*/ %{
/*定义全局变量,分别统计字符数,单词数和行数*/
int chars=;
int words=;
int lines=;
%}
%%
[a-zA-Z]+ { ++words; chars+=strlen(yytext);}/*正则表达式匹配任意单词,用字符串函数统计输入流中的当前字符数*/
\n { ++chars; ++lines; }/*遇到换行符,新的一行开始*/
. {++chars;}/*其它字符*/
%% main(int argc,char **argv)
{
yylex();/*调用flex生成的例程*/
printf("%8d%8d%8d\n",lines,words,chars);/*打印行号,单词数,字符数*/
}

  编译指令:

 $flex flexwc.l
$gcc -o flexwc -O3 flexwc

  下面是C代码,manwc.c:

 /*手工C代码的词数统计程序
manwc.c
*/ #include <stdio.h>
#include <ctype.h>/*使用isalpha()*/ /*全局变量,分别记录文件的字符数,行数和单词数*/
int i_char=,i_line=,i_word=; int main(void)
{
int inword=;
/*当inword==1时说明正在处理一个单词的内部(也就是一个单词还没结束)
否则意味一个单词的结束 */
char ch;
while ((ch=getchar())!=EOF)/*文件未结束*/
{
++i_char;/*增加字符数*/
if ('\n'==ch)/*行数*/
++i_line;
if (isalpha(ch) && !inword)/*一个单词的开始*/
{
inword=;
++i_word;
}
if (!isalpha(ch) && inword)/*一个单词的结束*/
{
inword=;
}
}
printf("%8d%8d%8d\n",i_line,i_word,i_char);/*打印文件行数、单词数、字符数*/
return ;
}

  编译指令:

 $gcc -o manwc -O3 manwc.c

  下面进行第一次测试,指令及结果如下:

 $time ./autowc < foo.txt

 real    0m0.014s
user 0m0.000s
sys 0m0.000s $ time ./manwc < foo.txt real 0m0.024s
user 0m0.000s
sys 0m0.000s

注意,因为flex的默认输入流和C代码的输入流都是stdin,所以这里用到了输入流重定向'<'。

  下面进行第二次测试,指令及结果如下:

 $time ./autowc < lex.yy.c 

 real    0m0.008s
user 0m0.004s
sys 0m0.000s $ time ./manwc < lex.yy.c real 0m0.008s
user 0m0.004s
sys 0m0.000s

  下面进行第三次测试,指令及结果如下:

 $time ./autowc < MAINTAINERS 

 real    0m0.013s
user 0m0.012s
sys 0m0.000s $ time ./manwc < MAINTAINERS real 0m0.019s
user 0m0.020s
sys 0m0.000s

  (此结果受机器影响较大,仅作为参考)

  经过三次规模从小到大的测试,可以看到用flex生成的词法分析器匹配正则表达式的速度几乎总是比手工C代码要快。可以预见,当模式变得更为复杂时,flex生成的代码的执行速度将会比纯手工C代码的效率高更多。这是由于flex处理正则表达式的内部格式(也就是确定性有穷自动机)使得匹配正则表达式时几乎与问题规模无关(也就是说并不是模式越复杂匹配的时间就会越久,但是也会有例外),而用手工的C代码处理此类问题时,总是倾向于将字符流一步步的进行分析,比如分析C语言中的'/'符号,当读入第一个'/'时,并不能确定到底是什么(有二义性),只有继续读接下来的一个字符:如果是一个数字,那'/'就是除法运算符;如果是‘/’那就是一个行注释,可以直接忽略本行余下的内容了;如果是'*'那还要判断什么位置出现了"*/",然后忽略中间的注释,如果找不到匹配的"*/",就需要报错。flex允许你对这三种方式定义明确的正则表达式:"/",“//”,“/*”(最后一种匹配/**/注释的情况还要用到起始状态的知识,这里就不介绍了)。总之记住一点:一次匹配一大段几乎总是比每次匹配一个字符、匹配多次要快,当然也有例外。

  总结:flex作为一种格式化文件处理工具,用它生成的代码不仅可以用于编译器解释器的编程人员的词法分析器开发,还可用于所有需要进行分析的格式化文件,比如快速查找文件中的某一特定格式、自动排版、代码自动缩进、语法着色等等,一切就看你能做什么了!

Flex的正则表达式匹配速度与手工代码的比较的更多相关文章

  1. 使用正则表达式匹配JS函数代码

    使用正则表达式匹配JS函数代码 String someFunction="init"; Pattern regex = Pattern.compile("function ...

  2. [No0000100]正则表达式匹配解析过程分析(正则表达式匹配原理)&regexbuddy使用&正则优化

    常见正则表达式引擎引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎有:DFA,NFA两种引擎. 引擎 区别点 DFA Deterministic finite autom ...

  3. 正则表达式匹配${key}并在Java中使用

    1.正则表达式匹配${key} \$\{([a-z]+)\} 能够匹配字符串中以${key}形式的文本(其中key为小写应为字母) .*\$\{([a-z]+)\}.* 可以用来检测文本中是否有${k ...

  4. [LeetCode] Regular Expression Matching 正则表达式匹配

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

  5. 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码

    正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...

  6. 在Visual Studio中使用正则表达式匹配换行和批量替换

    系统环境:Windows 8.1 Enterprise Update 2 x64 开发环境:Mircosoft Visual Studio Ultimate 2013 Update 2 RC 问题:如 ...

  7. .NET正则表达式匹配Silverlight

    这是一个.NET正则表达式匹配工具的Silverlight 在页面中加入以下代码就可以了: <"> <param name="source" value ...

  8. c# 正则表达式 匹配中括号&颜色过滤

    现在需要匹配 [color=#000000],以"[color"开头,以"[/color]"结束,中间字符数量不限制,最后返回所有匹配的下标. 代码如下: // ...

  9. *****正则表达式匹配URL

    最近将匹配URL的正则替换了下 之前的是: ((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3 ...

随机推荐

  1. Effective Java 75 Consider using a custom serialized form

    Principle Do not accept the default serialized form without first considering whether it is appropri ...

  2. 迷宫问题求解之“A*搜索”(二)

    摘要:在迷宫问题求解之"穷举+回溯"(一)这篇文章中采用"穷举+回溯"的思想,虽然能从迷宫的入口到出口找出一条简单路径,但是找出来的不是最优路径.因此本文采用A ...

  3. Swing应用开发实战系列之一:自定义JdbcTemplate

    笔者本人真正意义上接触编程开发是在2004年,最早用的就是VB,然后是Delphi等,后来转到.Net,中间断断续续还用过PowerBuilder等,无一例外,所研发设计的项目或系统都是WinForm ...

  4. hibernate集合类型映射

    Set无序 元素不可重复 List有序 元素可重复 Bag无序 元素可重复 Map键值对 Student: package model; import java.util.Set; public cl ...

  5. 手工搭建Openvpn

    环境: CentOS 6.4 (final) x86_x64 gcc-4.4.7-16.el6.x86_64 gcc-c++-4.4.7-16.el6.x86_64 lzo-2.03-3.1.e16_ ...

  6. java 基础

    一 4类8种基本数据类型 逻辑型   - boolean 文本型   - char 整数型   - byte short int long 浮点数型 - float double ☆java各整数类型 ...

  7. virtualbox 在window10上的兼容性调整

    更新完windows10后,打开当时的virtualbox 4.3.3已经是最新的啦,打开原来安装的几个虚拟机(hadoop),发现均失败. 打开setting一看,网络一栏有问题,桥接模式的虚拟机都 ...

  8. MyDiary,《你的名字。》同款日记应用

    新海城导演的新作<你的名字.>已经于 12 月 2 日在国内公映,这部评价极高的动画电影无论在剧情还是美术上都相当出色,是一部不容错过的好片.如果你还没有看过,赶快趁着还没下档买票去看看吧 ...

  9. [编]IoT The Internet of Things (IoT) 物联网

    物联网是新一代信息技术的重要组成部分.其英文名称是“The Internet of things”.由此,顾名思义,“物联网就是物物相连的互联网”.这有两层意思:第一,物联网的核心和基础仍然是互联网, ...

  10. cri-o 创建非infra容器

    1.// cri-o/server/container.go // CreateContainer creates a new container in specified PodSandbox fu ...