百科问答小站 logo
百科问答小站 font logo



如何从零写一个正则表达式引擎? 第1页

  

user avatar   luikore 网友的相关建议: 
      

是的, 首先要确定实现的目标, 有几个关键目标是会影响你的实现的

- 要不要支持完整的正则文法? (如果不支持 "|", 几十行就能搞定, 如果要支持完整的正则文法, 就需要一个能力超越正则的解析器, 如果要编写一个高效的 one-pass 正则编译器, 还是要学不少编译技术的...)

- 要不要支持 unicode 及 unicode character class? (扫描 UTF-8/16 码点会比较蛋疼, 容易一点的做法是转换成 UTF-32 做), 要对 unicode 做完整支持的话, 很多传统正则引擎里基于字节的匹配方式就不能做了, 一些 DFA 节点的表示方式和压缩手段也会受限制.

- 要不要支持 back reference? (如果你要实现 back reference 的话, 你不能用

Implementing Regular Expressions

里描述的 ThompsonVM/PikeVM 的, thread list 占有的内存会随着状态数指数增长而爆裂) 支持 back reference 的正则基本很多会退回去扩展最原始那个 Henry Spencer VM...

- 要做成 NFA based, DFA based, 还是一个字节码虚拟机? 对虚拟机的解决方案, 你要学习字节码解释器的基本构造, 可能会用 direct threading 等技术去做优化. 字节码可以看作线性化的 NFA, 相比构造 NFA 节点会减少一些 cache miss 但是相应的就不能使用很多节点压缩和优化的手段了.

- 要不要做一个 JIT 引擎? 这个更令人兴奋, 可以参考

ytljit/regexp.rb at master · miura1729/ytljit · GitHub

)

- 要不要兼容 POSIX 标准里的正则部分? (估摸至少 4000 行代码, 自己考虑工作量咯)

- 要不要做 extended 正则?

所谓 extended 正则, 就是还支持补集和交集运算, 正则语言这么搞完结果还是个正则语言, 就是实现 grep -v 之类的可以简单一些, 可以尝试

这个方法

- 要不要做 Online Parsing?

online parsing 常用于语法高亮和大文件解析中. 其意思是输入一部分内容就匹配一部分, 有新内容输入的时候你不该重头匹配一遍 (每敲一个字符重新着色一遍太慢了), 而是做最低限度的回溯. 如果要做 online parsing, 那么怎么暂停你的 VM, 怎么缓存回溯都是要考虑的问题. 而且正则的语法会有限制.

- 要不要支持超巨大的正则表达式?

有些 network filter 例如联邦的防火墙, 会有几十万条规则, 你会发现普通的办法在 20G 内存的机器上都编译不了这个正则... 不过用小内存支持 DFA 千万节点的方法已经有人研究出来了: D^2FA... 为了编译出这么大的 D^2FA, 其编译期算法也有人研究过了:

D^2FA

- 要不要支持以下各种正则引擎的 fancy feature?

-- X 匹配字素

-- 递归 named group

-- capture history

-- nested capture

-- atomic group

-- greedy vs reluctant vs possessive

...

每一项都相当有难度... 尤其是 greedy/reluctant/possessive 的区别有可能从根本上颠覆你这个正则引擎的实现, 很多人的正则引擎做完 DFA/NFA 就停下来了, 也是因为搞不动这些 feature.

---

OK, 目标明确了, 开始代码之前要先夹沟夹沟哦, 建议: 不要一开始就想把它做得很高效率, 要把问题拆得足够小足够简单的来做, 只要决定好大方向不错, 就不用推倒重来很多次了...

现在的正则引擎的构造比各种 parser generator 都要复杂, good luck!

推荐书籍: Parsing Techniques - A Practical Guide 2008 (讲得比较全了, 就是缺少 coroutine based parser 的构建)

推荐课程:

Parsing Beyond Context-Free Grammars

(为什么要 beyond CFG 呢? 因为现在正则引擎的能力已经 beyond CFG 啦)

推荐代码: Henry Spencer's regexp engine

regexp.old/regexp.c at master · garyhouston/regexp.old · GitHub

是很多现代流行的正则引擎的始祖, 解释器实现, 很多新 feature 能扩展得得进去, 也有混合 DFA 的优化

Onigmo

k-takata/Onigmo · GitHub

是 Ruby 的正则引擎, 特点是 encoding aware 兼容多种语法和 feature, 如果要做 unicode character class 可以抄它的...




  

相关话题

  【C#】this 关键字限定本地类型的成员? 
  什么才算是真正的编程能力? 
  C++ 实现接口与实现分离后,文件变得更多了,到底有什么好处? 
  室友想抄我的代码,给还是不给? 
  为什么程序比较难写、bug 比较难调呢? 
  亲爱的程序员们,一天写多少代码才算达标? 
  为什么 C++ std::map::operator[] 不提供 const 版本? 
  链表和数组的插入删除时间复杂度都是o(n),为什么教材网络上说链表效率高? 
  有什么像a=a+b;b=a-b;a=a-b;这样的算法或者知识? 
  能看得懂编程,但自己写却一点都写不出来怎么办? 

前一个讨论
计科学生能成为b站稚晖君这样软硬兼通能diy电子产品的人吗?
下一个讨论
CPU的功耗和什么相关?为什么一个while(1);就可占满CPU的功耗?





© 2024-12-25 - tinynew.org. All Rights Reserved.
© 2024-12-25 - tinynew.org. 保留所有权利