CTRE-01-基本原理

Compile Time Regular EXpression(CTRE)是一个在编译期生成正则表达式(Regex)匹配器的C++库。因为是在编译期对表达式进行构建,这比很多运行期构建的regex库要高效很多,而且代码——包括生成的汇编——也更简洁易读,效果像这样:

bool matched = ctre::match<"[0-9]*">(str);

当然class模版参数(Non Type Template Parameter)是C++20的特性,C++17不能这样用,而应该传入一个static对象的引用给模版。

经过一番搜索,我发现网上关于CTRE的学习资料几乎等于没有,甚至关于模版编程也只有大神们偶尔贴几段代码,一点解释都没有。这里我尝试重新造一遍此轮子,希望能帮到也想学习Metaprogramming的你。

在模版编程前,我们先了解一下Regex的原理。

正则表达式(Regex)

Regex的语法其实非常简单,Regex可以是

  • 空集,即什么都没有
  • 空字符串\(\epsilon\),这与空集不同,\(\epsilon\)表示不匹配任何字符
  • 一个字符,如a
  • 两个Regex的连接(Concatenation),我们用一个点表示:A·B
  • 两个Regex的Alternation(不知道怎么翻译了),我们用竖线表示:A|B
  • 一个Regex的重复,我们用星号(Kleene star)表示:A*

注意我们使用的Regex中,a?是(\(\epsilon\)|a)的“缩写”,a+是(a·a*)的“缩写”。我们一般还省略Concat的点号。

这个语法足以构建我们一般使用的基本的Regex,当然高级特性如capture group不包含在这语法里。

LL(1) parser

要构建Regex,首先要用parser将输入的字符串转换成AST形式。由于 我还没学编译原理,只知道LL(1) Regex语法属于LL(1)语法,所以我们选择简单的LL(1) parser即可。

LL(1) parser只需要一个parse table,而parse table由\(Firsts\)\(Follows\)得到,可以看这里的解释。其中用到的语法表达形式叫Context Free Grammar (CFG),可以看这里的解释。

有个稍微不好理解的地方是:如果\(T'\rightarrow FT\),且\(T\)是Non-terminal,那么\(Follows(F)=Firsts(T)\)。如果\(Firsts(T)\)含有\(\epsilon\)(空字符),则\(Follows(F)\)就包含\(Follows(T)\)中所有terminal。这是因为\(\epsilon\)表示\(T\)可以转换为空字符,如果\(T\)是空的,那么跟在\(T\)后的terminal就相当于跟在\(F\)后。

有了parse table后,就可以根据它进行stack的push和pop操作了。

有限状态机

Regex的匹配一般是通过有限状态机(Finite Automata, FA)进行的。

FA由4元组描述:(有限个状态,状态转移条件,一个起始状态,一或多个终止状态)。

FA从一个初始状态开始,然后根据状态转移条件转移到下一状态,直到到达终止状态,可以看这个解释。对Regex来说,到达输入末端时,FA处于终止状态就代表匹配成功。

[0-9]+生成的FA,双圈的圆表示终止状态:

实际生成FA时是不断地进行小FA的连接,连接的方法其实不太简单,写到这部分再说。

还有一个问题是,FA可能存在同时可以进行几个状态转移的情况,这样的FA称为Non-determinestic FA(NFA),匹配NFA需要同时考虑多个状态转移进行搜索,导致效率低。于是就出现如何将NFA转换为状态转移路径可以唯一确定的Determinestic FA(DFA)的问题,这个问题也不简单,以后再说。

总结

总结一下我们需要实现些什么,首先计算都是编译期进行的,所以所有数据结构都要支持constexpr

  1. 模版参数Regex是一个字符串,这个字符串在编译期即确定,所以我们需要大小固定的字符串对象:class FixedString
  2. 一个通过重载规则描述的parse table:struct ParseTable
  3. LL(1) parser需要的编译期栈:class Stack
  4. 一个能够表示AST的表达式模版(expression template)
  5. 有限状态机本身:class FiniteAutomata
  6. 有限状态机的运行期匹配机制
  7. 有限状态机需要的集合容器,同样在编译期即确定:class FixedSet
  8. 状态转移的表示
posted @ 2020-11-07 16:20  RelaxDude  阅读(646)  评论(0)    收藏  举报