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 ...
随机推荐
- oracle REGEXP_SUBSTR函数
REGEXP_SUBSTR函数格式如下: function REGEXP_SUBSTR(String, pattern, position, occurrence, modifier) __srcst ...
- SQLite数据操作
1.向学生表中插入100条数据 2.按条件查询学生数据 3.修改学生数据 4.删除学生数据 import UIKit class ViewController: UIViewController { ...
- jQuery Validate 表单验证插件----自定义一个验证方法
一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW 访问密码 f224 二.引入依赖包 <script src="../../scripts/j ...
- nyoj 139 我排第几个--康拓展开
我排第几个 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 现在有"abcdefghijkl”12个字符,将其所有的排列中按字典序排列,给出任意一种排列,说 ...
- 边工作边刷题:70天一遍leetcode: day 74
Binary Tree Upside Down 要点: recursion反转如何做?两个要点,一是在递归之后反转link(因为先要通过原来的link到下一层),二是要一层层把最底层的root返回来. ...
- Unity抗锯齿
Unity抗锯齿设置是针对模型,对模型的阴影的锯齿设置无效,不知道我这样的理解是否正确. 遇到的问题 而我是要对灯光照射在模型上产生的阴影进行抗锯齿,暂时还未研究出解决方案,希望知道的朋友告知一声. ...
- meate 标签使用介绍
//禁止浏览器从本地计算机的缓存中访问内容 <meta http-equiv="pragma" content="no-cache"> //清楚缓存 ...
- rsync+inotify实时同步环境部署记录
随着应用系统规模的不断扩大,对数据的安全性和可靠性也提出的更好的要求,rsync在高端业务系统中也逐渐暴露出了很多不足.首先,rsync在同步数据时,需要扫描所有文件后进行比对,进行差量传输.如果文件 ...
- 在Function对象上扩展method方法
;(function() { /** * 在Function对象上扩展method方法 * @param {String} name 扩展的方法名称 * @param {Function} callb ...
- 【转】【Asp.Net】Asp.net发送邮件的两种方法小结
这几天看了一下Asp.net发送邮件方面的东西,记得之前的IIS6上有SMTP服务器,可以直接利用这个进行邮件发送,现在的开发环境是Windows 7,找了半天没有找到,到网络上查了才知道原来wind ...