如何使用组名使用正则表达式实现高效的分词器

Posted

技术标签:

【中文标题】如何使用组名使用正则表达式实现高效的分词器【英文标题】:How to implement an efficient tokenizer with a regex, using group names 【发布时间】:2019-03-19 01:41:48 【问题描述】:

我正在尝试编写一个标记器,用于使用正则表达式解析文本正文(输入字符串)。我想要的是将输入拆分为单个令牌并将它们存储在 List 中,其中令牌是一个(C#)类,如

class Token 
  string value;
  string type; // "identifier", "string', "intliteral', ... 

我想使用如下所示的正则表达式来拆分输入字符串:

public static Regex tokenPattern = new Regex (
@"
  ( (?<identifier>(?:\pL|_)\w*)
  | (?<string>""[^""]*"")
  | (?<intliteral>(?:-|\+)?\d+[^\.])
  | (?<realliteral>(?:-|\+)?\d+(?:\.\d+)?)
  | (?<comma>,)
  | (?<lpar>\()
  | (?<rpar>\))
  | ...
  | (?<undefined>[^\s]*?)
  )
",
  RegexOptions.ExplicitCapture |
  RegexOptions.IgnorePatternWhitespace | 
  ...
);

我的问题是获取每个Token的value部分很容易,但是获取type部分似乎没有简单的方法,即组名。我预计 Regex Group 会有一个包含“标识符”等的 Name 属性,但事实并非如此。

有没有一种方法可以确定组名,而无需遍历每个令牌的所有组名/编号? (即复杂度为 O(n) 而不是 O(nm) 的方法,输入字符串中有 n 个令牌,有 m 个令牌类型)?

【问题讨论】:

根据this documentation Group 确实有一个Name 属性。但我不知道这是否真的对你有帮助,因为GroupCollection 似乎有所有组,匹配与否。 是的,这就是问题所在。 GroupCollection 包含所有组名称,而不仅仅是匹配所属组的名称 编写词法分析器可能不是正则表达式库的主要预期用例。有诸如 Flex 之类的工具可用于生成高效的词法分析器,我很确定您可以找到 C# 端口。但是我使用了与您在此处描述的相同的技术在 javascript 中编写 q&d 词法分析器,它工作得很好,尽管将模式的数量减少到最低限度是值得的。在 JS 中,您可以使用全局搜索和替换进行词法循环,因为您可以使用函数作为替换 arg。我不知道 C# 是否这样做。 ...但它仍然是 O(nm),因为被调用的函数需要检查其参数以找到实际匹配的参数。 感谢您的回答。我要去看看Flex。实际上 TypeScript / JavaScript 是我的目标语言。 【参考方案1】:

这将是一个多阶段操作,使用一个正则表达式来执行这样的操作不会很好地利用处理器时间。我的建议是划分操作的各个阶段,例如:

    使用基本正则表达式将每个值解析到令牌中。 具有特定的操作来识别遇到的令牌类型并相应地设置该值。

大多数情况下,您必须在第 2 步之后继续打破这些步骤才能提高效率。


我必须同意这样的观点,即正则表达式不是用于令牌语言处理过去识别单个令牌或在令牌进程中子识别令牌属性的工具。

【讨论】:

感谢您的回答,我知道这种两阶段方法,我的问题正是如何避免它。这就是我所说的 O(n) 而不是 O(nm)。

以上是关于如何使用组名使用正则表达式实现高效的分词器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 DFA 正则表达式匹配器实现正则表达式断言/环视(即 \b 样式字边界)

正则表达式 65 CPL 和无分词

Boost 正则表达式:获取命名组

流数据的高效(基本)正则表达式实现

Python 中正则表达式全部语法速查

如何使用正则表达式拆分字符串而不消耗拆分器部分?