1、前言

  《Linux使用ragel进行文本快速解析(上)》文中对Ragel进行了初步介绍,并给出了一个atoi的例子,本文接着再给出一个文本行解析的例子

2、思路

  awk的主要是对固定列数的文本进行内容解析,若使用 awk命令的话,是进行逐行解析。同样的,使用 Ragel 写的思路也是,编写正则以行为单位,进行读取解析。但是相比命令的方式,Ragel 相当于可编程处理,则能灵活地对不固定行的文本进行处理。

3、源码

  代码的实现在ragel-6.10/examples/awkemu.rl

先看状态机这块的代码:

%%{machine awkemu;action start_word {ws[nwords] = fpc;}   action end_word {we[nwords++] = fpc;}   action start_line {nwords = 0;ls = fpc;}   action end_line {printf("endline(%i): ", nwords );fwrite( ls, 1, p - ls, stdout );printf("\n");for ( i = 0; i < nwords; i++ ) { printf("  word: ");fwrite( ws[i], 1, we[i] - ws[i], stdout );printf("\n");}   }   # Words in a line.word = ^[ \t\n]+;# The whitespace separating words in a line.whitespace = [ \t];# The components in a line to break up. Either a word or a single char of# whitespace. On the word capture characters.blineElements = word >start_word %end_word | whitespace;# Star the break line elements. Just be careful to decrement the leaving# priority as we don't want multiple character identifiers to be treated as# multiple single char identifiers.line = ( blineElements** '\n' ) >start_line @end_line;# Any number of lines.main := line*;
}%%%% write data noerror nofinal;

可以看出,行由多个元素组成: line = ( blineElements** ‘\n’ ) >start_line @end_line;

元素由单词、分隔符进行区分: blineElements = word >start_word %end_word | whitespace;

代码中获取字符串的动作并没有进行内存拷贝,而是通过暂存字符串指针到数组 ws we 保存。

再看一下主函数的入口:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXWORDS 256
#define BUFSIZE 4096
char buf[BUFSIZE];int main()
{int i, nwords = 0;char *ls = 0;char *ws[MAXWORDS];char *we[MAXWORDS];int cs;int have = 0;%% write init;while ( 1 ) {char *p, *pe, *data = buf + have;int len, space = BUFSIZE - have;/* fprintf( stderr, "space: %i\n", space ); */if ( space == 0 ) {fprintf(stderr, "buffer out of space\n");exit(1);}len = fread( data, 1, space, stdin );/* fprintf( stderr, "len: %i\n", len ); */if ( len == 0 )break;/* Find the last newline by searching backwards. This is where* we will stop processing on this iteration. */p = buf;pe = buf + have + len - 1;while ( *pe != '\n' && pe >= buf )pe--;pe += 1;/* fprintf( stderr, "running on: %i\n", pe - p ); */%% write exec;/* How much is still in the buffer. */have = data + len - pe;if ( have > 0 )memmove( buf, pe, have );/* fprintf(stderr, "have: %i\n", have ); */if ( len < space )break;}if ( have > 0 )fprintf(stderr, "input not newline terminated\n");return 0;
}

主函数是读取文件内容,通过调用 %% write exec; 将内容传到状态机中进行解析,

开始一看还是挺复杂的,为啥不考虑通过 fgets读取一行进行处理?所以又进行修改试验。

int ragel_awkemu(const char *str)
{const char *p = str, *pe = str + strlen(str);int cs; int i, nwords;const char *ls = NULL;const char *ws[MAXWORDS] = {NULL};const char *we[MAXWORDS] = {NULL};/* Initialize and execute. */%% write init;%% write exec;return nwords;
}int main(int argc, char *argv[])
{char buf[SIZE_LINE_NORMAL];while (fgets(buf, sizeof(buf), stdin) != 0) {int value = ragel_awkemu(buf);printf("num: %d\n", value);}   return 0;
}

4、运行

  首先简单地测试,两种方法都能进行文本解析。为了压测两种方法的真正能力,造了100w行的日志信息到文件里,一行15列数据,总文件大小为300MB。

原版,按块取:

centos-x64 [ ~ ]# time ./awkemu < /tmp/syslog.dat >/dev/null
real    0m2.581s
user    0m2.484s
sys     0m0.094s

修改版,按行取:

centos-x64 [ ~ ]# time ./awkemu2 < /tmp/syslog.dat >/dev/null
real    0m3.488s
user    0m3.372s
sys     0m0.111s

  性能方面,速度达到30~40w/s的速度。同时,可以看出行解析稍微慢了一些,但是通过strace查看时,不管fgets还是fread底层都是调用read接口,所以开销的区别并不在接口调用次数上。

  再仔细阅读对比一下main函数,最后分析开销的区别是再调用次数方面,还是fread以每次处理的数据多、调用次数少占优。每次读到(拷贝)一块大buffer,再通过状态机进行逐个字符解析。若碰巧最后几个字符不足整行的话,memmove 到buffer头进行下一次处理。

5、结论

  Ragel提供了一个经典的awk例子,同时也告诉我们,通过尽可能的块数据获取减少函数调用,尽可能减少内存拷贝,这样才能把性能发货到极致。

Linux使用ragel进行文本快速解析(下)相关推荐

  1. Linux内核很吊之 module_init解析 (下)【转】

    转自:https://blog.csdn.net/richard_liujh/article/details/46758073 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...

  2. Linux内核很吊之 module_init解析 (下)

    Linux内核很吊之 module_init解析 (下) 转载 2017年01月23日 13:58:21 标签: 95 编辑 删除 转自: http://blog.csdn.net/richard_l ...

  3. Linux用一键安装包快速部署禅道项目管理平台

    Linux用一键安装包快速部署禅道项目管理平台 简介:本文介绍如何在linux下面使用禅道一键安装包搭建禅道的运行环境. 一.安装 二.如何访问数据库 三.9.2.stable版本起Linux一键安装 ...

  4. linux软件包管理解析,linux学习笔记_09_软件包管理解析.doc

    linux学习笔记_09_软件包管理解析 软件包管理 软件包分类 源码包(C语言编写的源代码) linux主要由C语言来写. 源码包可以用写字板打开 脚本安装包:源码包进行再开发的源码包(提供安装界面 ...

  5. java csv快速解析_爸爸解析:闪电般的快速CSV解析体验

    java csv快速解析 总览 (Overview) With a plethora of options to parse CSV files/data and adding to it the i ...

  6. Linux中的简单文本处理

    文本处理命令 tr命令(可以用来删除一段文本信息中的某些文字,或者将其进行转换) 格式: tr [option] - SET1 [SET2] 可选参数: -d: 删除和set1匹配的字符 -s:去除s ...

  7. 如何浏览文本字段(下一个/完成按钮)

    如何使用iPhone键盘上的"下一步"按钮浏览所有文本字段? 最后一个文本字段应该关闭键盘. 我已经设置了IB按钮(下一个/完成),但现在我被卡住了. 我实现了textFieldS ...

  8. 手把手教你用 TensorFlow 实现文本分类(下)

    手把手教你用 TensorFlow 实现文本分类(下) 本文作者:AI研习社 2017-05-29 13:36 导语:文本分类全流程解析. 雷锋网(公众号:雷锋网)按:本文作者张庆恒,原文载于作者个人 ...

  9. linux sort 时间排序,linux sort多字段排序实例解析

    本文研究的主要是linux sort多字段排序,具体介绍如下. Linux多数发行版自带的sort程序,非常强大,在此只说多字段排序 sort 有个参数-k,可以指定字段,有比较复杂的语法,不在文本范 ...

  10. linux编辑文档windows,1.9vim编辑器linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是...

    1.9vim编辑器 linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是用命令去操作 这个工具分为三种模式:命 ...

最新文章

  1. 标题与文字的组合[摘]
  2. Boost:fork联接的测试程序
  3. 10如何成为卓越领导者摘录——卓越的领导者
  4. 飞秋(FeiQ)2012版择日发布
  5. python--二叉树库函数
  6. github上创建java项目简单操作
  7. 中年男人的唯一出路就是安分守己
  8. Log4j2 Zero Day 漏洞 Apache Flink 应对指南
  9. .bin文件如何打开并使用
  10. Android Studio User Manual
  11. 测试人员在工作中如何查日志?
  12. EagleEye的特性分析
  13. 聚合数据API接口调用方法
  14. seo关键词优化的技巧
  15. 畅想未来计算机和人工智能的应用,人工智能在生活中的应用及展望
  16. 帝国cms小程序端源码
  17. r语言中的或怎么表示什么不同_R语言中$是什么意思
  18. Zxing和QR CODE 生成与解析二维码实例(普通篇)
  19. R语言大数据分析纽约市的311万条投诉统计可视化与时间序列分析
  20. matlab之请求用户输入函数input

热门文章

  1. 线性回归之最小二乘法公式推导和原理介绍
  2. 关于系统集成的设计方案(一)
  3. Python获取微信好友地址以及性别并生成可视化图表
  4. IGH_Master主站配置驱动伺服电机和变频器总结
  5. java毕业设计医院管理系统Mybatis+系统+数据库+调试部署
  6. netperf测试最大连接数
  7. 金园云化工园区智慧应急解决方案
  8. ZigBee 集中式网络与分布式网络
  9. 考勤系统 服务器管理,zktime5.0考勤管理系统
  10. 网速测试软件win10,win10系统测试网速的操作方法