如何在Python(第6部分:发动机)构建正则发动机
#编程 #教程 #python #regex

终于是时候写关于我们构建的正则发动机的引擎了。

正如我们已经看到的,解析器由于解析正则表达式而产生AST。


现在,引擎必须检查给定的字符串是否匹配等级。

为此,发动机使用正则表达式的AST表示,提取正则表达式的基本特征/元素,并尝试找到测试字符串是否具有它们。 /p>

引擎

引擎再次是Python类,具有基本方法匹配,它是包含引擎和所有所需辅助方法的封闭。

匹配签名:

def match(self, re: str, string: str)

匹配语义

我们将向匹配方法提供的语义是:

  • 它在字符串中的第一次出现时返回
  • 如果没有匹配,它将再次尝试将输入字符串移动到右侧(即将字符串一个字符移动到右侧),直到到达字符串的末端。

也就是说,如果输入字符串为abac,而正则正则是c,则在第一次尝试abac the the t the t Match c上,所以再次尝试,但是这次将abac转移到右边,所以尝试匹配bac带有c,导致另一个失败,因此它再次尝试使用acc(失败),最后,它与c一起尝试c,从而导致匹配,从而返回true。

The  raw `match` endraw  function so far.

到目前为止的match功能。

如何匹配

match_group是发动机的最重要方法。

它通过迭代AST节点的孩子而起作用,并在找到GroupNode或有一些差异时递归地调用自己。

如果找到了OrNode,它将检查左子女(位置0中的一个)是否匹配,如果没有,则尝试正确的一个。

当找到叶节点(ElementNode,â€)时,它会尝试匹配。

每场比赛后,匹配字符的str_i(字符串索引)增加了。


字符串索引设置为位置0(或一般要考虑更多的位置),并且是一个全局变量,但是匹配函数的本地变量。

递归呼叫的机制使您可以轻松地管理树上的弦和字符串中的点。它还使您可以将每个组视为一个单独的实体,从而更轻松地遵循代码执行。

显然,这不是整个引擎,因为如第一篇文章所述,我们将需要一个回溯系统来确保探索与字符串匹配的所有可能路径。

一个小问题

实际上,叶节点和群体的语义是默认情况下将它们与最大的角色相匹配,尽管大多数情况下这很方便,但在某些边缘情况下,这不会导致一个正确答案。

让我们检查这个示例:

如果您有正则a+ab和一个测试字符串aab

  • 由此产生的AST将由一个GroupNode组成,有三个孩子,所有叶子
  • 第一个要匹配的a [1, +â[times
  • 第二次匹配的第二个a
  • 最终的b可以完全匹配一次。

在执行我们的匹配函数期间,这将发生:

  • match_group被称为并开始迭代其子女
  • 第一个a元素尽可能匹配,所以两次aa
  • 然后,引擎试图匹配第二个a元素,但它失败了,因为现在唯一的左字符是b
  • false将被返回,但我们都知道正确答案是正确的。

这是因为我们对匹配函数的语义给出了。我们希望系统要做的是尝试另一种方法:

  • 由于第一个元素可以接受1个或更多的字母a,它与其中的两个相匹配,所以我们想告诉它 - 嘿,请尝试一次尝试一下<< /li>
  • 在这种情况下,第一个a将匹配一次,留出足够的空间适合第二个a元素,然后还有b元素,我们的第三和最后一个
  • 这个过程有效,因此答案是正确的。

此过程称为回溯,将成为下一篇文章的主题,现在,让我们忽略问题。

结论

总的来说,我们涵盖了我们所需的几乎所有内容以解释比赛方法的行为。

我们代码的骨架看起来像这样

 raw `match` endraw  function’s structure.

match函数的结构。

在下一篇文章中,我们将介绍回溯有趣的主题,并将完成我们的正则引擎。