Flex的正则表达式匹配速度与手工代码的比较
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的正则表达式匹配速度与手工代码的比较的更多相关文章
- 使用正则表达式匹配JS函数代码
使用正则表达式匹配JS函数代码 String someFunction="init"; Pattern regex = Pattern.compile("function ...
- [No0000100]正则表达式匹配解析过程分析(正则表达式匹配原理)&regexbuddy使用&正则优化
常见正则表达式引擎引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎有:DFA,NFA两种引擎. 引擎 区别点 DFA Deterministic finite autom ...
- 正则表达式匹配${key}并在Java中使用
1.正则表达式匹配${key} \$\{([a-z]+)\} 能够匹配字符串中以${key}形式的文本(其中key为小写应为字母) .*\$\{([a-z]+)\}.* 可以用来检测文本中是否有${k ...
- [LeetCode] Regular Expression Matching 正则表达式匹配
Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...
- 正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码
正则表达式匹配/data/misc/wifi/wpa_supplicant.conf的WiFi名称与密码: String regex_name="ssid=\"(.*?)\&quo ...
- 在Visual Studio中使用正则表达式匹配换行和批量替换
系统环境:Windows 8.1 Enterprise Update 2 x64 开发环境:Mircosoft Visual Studio Ultimate 2013 Update 2 RC 问题:如 ...
- .NET正则表达式匹配Silverlight
这是一个.NET正则表达式匹配工具的Silverlight 在页面中加入以下代码就可以了: <"> <param name="source" value ...
- c# 正则表达式 匹配中括号&颜色过滤
现在需要匹配 [color=#000000],以"[color"开头,以"[/color]"结束,中间字符数量不限制,最后返回所有匹配的下标. 代码如下: // ...
- *****正则表达式匹配URL
最近将匹配URL的正则替换了下 之前的是: ((http|ftp|https)://)(([a-zA-Z0-9\._-]+\.[a-zA-Z]{2,6})|([0-9]{1,3}\.[0-9]{1,3 ...
随机推荐
- SQL Server 2008 R2——VC++ ADO 操作 重复利用_CommandPtr
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- Web Service中的几个重要术语
WSDL:web service definition language 直译:WebService定义语言 1.对应一种该类型的文件.WSDL 2.定义了Web Service的服务器与客户端应用交 ...
- JS高级程序设计2nd部分知识要点4
ECMAScript中所有函数的参数都是按值传递的. 5种基本数据类型: Undfined,Null,Boolean,Number,String. ECMAScript中的所有参数传递的都是值,不可能 ...
- VirtualBox: Effective UID is not root (euid=1000 egid=100 uid=1000 gid=100)
桌面上运行virtualbox出错: The virtual machine 'xp' has terminated unexpectedly during startup with exit cod ...
- git_sop 脚本使用说明
tags : git 前言 脚本下载地址: git是功能非常强大的版本管理工具,同时它带来的是学习成本的上升.最近我们团队的部分项目采用了git进行版本管理,一部分小伙伴对于git使用不是很熟悉.一方 ...
- OpenStack三个节点icehouse-gre模式部署
一.环境准备 1.架构 创建3台虚拟机,分别作为controll节点.network节点和compute1节点. Controller节点:1processor,2G memory,5G storag ...
- 【问题&解决】sql2012安装时卡在正在启动操作系统功能"NetFx3"上不动的解决办法
安装完windows8 后开始安装sql2012,安装过程中停在“正在启动操作系统功能"NetFx3"”不动了,很是着急,于是上网查了一下资料,原来NetFx3指的是Framewo ...
- hihocoder-1391&&北京网赛09 Countries(优先队列)
题目链接: Countries 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 There are two antagonistic countries, country ...
- codeforces 711A A. Bus to Udayland(水题)
题目链接: A. Bus to Udayland 题意: 找一对空位坐下来,水; 思路: AC代码: #include <iostream> #include <cstdio> ...
- Linux命令学习-date
date命令可以用来显示和修改系统日期时间,注意不是time命令. 1.在命令行输入date显示当前时间 [root@vm4 logs]# dateSat Nov 22 00:00:02 CST 20 ...