【问题标题】:Accept a regular expression and produce an NFA (Java)接受正则表达式并生成 NFA (Java)
【发布时间】:2012-09-14 10:39:53
【问题描述】:

我正在尝试编写一个程序来接受描述正则表达式的字符串。例如:

10(0U1)*

其中 U 是联合运算符,* 是 Kleene 星号(我们还可以看到隐含的串联)。

我考虑过标记字符串的原子并根据运算符和操作数构建机器。我想用类似于下面的规则对每个原子进行算法操作:http://www.cs.may.ie/staff/jpower/Courses/Previous/parsing/node5.html

我不确定如何以智能方式最好地解析这种类型的输入,以便以编程方式构建 NFA。

我的程序的目标是接收上述输入并输出将由其 5-touple 描述的相应 NFA。非常感谢任何有关实现该目标的建议。

【问题讨论】:

  • 如果您尝试实施 NFA……它将如何运作?你会有大规模并行硬件来运行它吗?还是您会先在内部转换为 DFA?
  • 很久没学计算理论了。 :) 这些正则表达式中是否有“操作顺序”?如果是这样,我可能会从我的解析开始(即,假设 Union 具有最高优先级......然后找到所有的 Unions,执行这些操作,转到下一个运算符等)
  • bdares:模拟 NFA 有一个几乎微不足道的算法(Dragon 中的算法 3.4,尽管在大多数算法教科书中都可以找到一些变体);它经常被用来引入双端队列的概念,(因为它很自然地适合,尽管龙算法只使用两个堆栈)。回到 grep、egrep 和 fgrep 都是独立程序的时代,grep 使用它(在 Thompson 构造生成 NFA 之后)。

标签: java regex parsing nfa


【解决方案1】:

如果您可以使用外部库,最好让现代解析器生成器(例如 ANTLR)完成所有解析工作,并为您的正则表达式提供一个抽象语法树,即使它是一种相对简单的语言。

否则,如果您需要从头开始编写它,则需要首先确定是否需要分词器(或“词法分析器”)。如果您的语言由单字符标记组成(如您的示例中所示),那么您可以安全地跳过编写标记器,而只需遍历字符串中的字符。然后你必须编写解析器,一个扫描令牌列表并构建语法树的大循环。

在任何情况下,您都应该得到这样的语法树,例如10(0U1)*

请注意,在语法树中,所有括号和隐式优先规则都消失了,它们被树的结构所取代。

之后,您必须递归地将树转换为 NFA 图。

这是一种可能的方法的粗略草图。

为每个语法节点类型编写一个翻译方法。该方法将以其开始和结束 NFA 状态作为参数调用,后者是可选的。该方法将绘制自己的图形片段,并酌情调用其子级的翻译方法,并返回其结束状态(可能已作为参数省略,因此调用者不知道。)

  • 创建一个起始状态并调用语法树根节点的翻译方法,将起始状态作为其起始状态传递给它。
  • 文字语法节点(在您的示例中为 0 和 1)将从其起始状态绘制一个箭头到其结束状态,如果未提供,则创建一个新的结束状态:
  • 星节点将调用其子节点的转换方法,将其自己的起始状态作为子节点的开始和结束状态(这样 NFA 将能够根据需要多次“循环”该状态。)
  • concat 节点将调用第一个子节点,为其提供起始状态但没有结束状态;然后它将调用第二个孩子,将第一个孩子的结束状态作为起始状态传递给它;依此类推,构建一个单向子图序列,每个子图一个。

你应该明白了。

在您将 NFA 图构建为状态的链接结构(并且可能将其显示为实际图,以用于调试或文档目的)后,您可以将其转换为正式的元组并输出。

【讨论】:

    猜你喜欢
    • 2019-03-16
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多