正则表达式的算法 - 或上的组合
Algorithm for regular expressions - combinations on or
我正在开发一个C++应用程序,首先解析正则表达式字符串,然后使用它执行一些计算。是否有任何现有的算法可以输出长度为 L 的字符串的数量 N,这些字符串可以被给定的正则表达式(例如 (a|ab)* | (aa|bb)*
(识别?或者是否有一个数学公式,我可以使用,例如涉及阶乘的公式?我只想获取给定数字 L 的此类正则表达式短语可以识别的字符串的 N 个(a|ab)*
示例。我认为答案是5。但是对于大量的L,我想知道是否有任何算法或数学表达式可以计算出来。
这是一种基于矩阵幂的高效算法,可用于计算这些数字。
我只给出一个高级描述,而不是代码。
-
首先,你想使用计算机科学基础中一个众所周知的等价,即(简单(正则表达式等价于有限状态机。
(回想一下,有限状态机本质上是一个流程图,其中从每个节点开始,字母表中的每个字母都有一个标记的边缘到某个特定的其他节点(或者它可能是一个循环(。此外,状态的某些子集称为"接受集",流程图中的某些特定状态称为开始状态。字符串被称为在有限状态机中诱导路径,方法是从开始状态开始并连续跟随标记的边。如果最终状态在接受集中,则计算机
accepts
字符串,否则rejects
字符串。经典构造表明,从任何正则表达式中,我们可以构造大小相似的有限状态机,从任何有限状态机中,我们可以构造大小相似的正则表达式。任何对应于正则表达式的语言(所有有限字符串的子集(都称为"正则",并且当且仅当语言对应于有限状态机时,该语言才是正则的。例如,如果我有一个字母
{a,b,c}
,正则表达式(a|b)*
,它对应于具有两种状态的机器。开始状态有一个标记为a
的循环,一个标记为b
的循环,以及一个标记为c
到第二个状态的箭头。第二个状态有三个循环,所以如果你去那里,你就会被困住。接受集仅包含启动状态。程序的第一步是将正则表达式转换为相应的有限状态机。(可能是一些现有的正则表达式库基本上已经这样做了,我认为 PCRE 可能会,尽管我不确定。
-
给定一个有限状态机,我想构造一个相应的随机矩阵。在这个矩阵中,每个状态都有一行,每个状态都有一列,每个条目都是一个概率。在条目
(i,j)
时p_{i,j}
的概率等于如果我在状态i
,并且我随机阅读一个字母,我下一个进入状态j
的概率。因此,对于我给出的示例,矩阵是[ 2/3 1/3 ]
[ 0 1 ] -
如果你想了解长度为
k
的字符串,那么使用矩阵幂,计算矩阵M^k
其中M
是上面的概率转换矩阵。 -
最后,如果
q
是开始状态,则将接受集中s
的每个状态M^k_{q, s}
的所有条目相加。这些概率的总和正好等于正则表达式接受长度为k
的随机字符串的概率。因此,您可以通过乘以N^k
来获得此类字符串的数量,其中N
是字母表中的字母数。
我认为这个算法的存在并不难,但也不是微不足道的,我曾经在计算理论课的期末考试中给出了一个更难的版本作为额外的学分问题。我不知道它的任何现有实现,有兴趣知道。
当你使用矩阵幂时,你以这种方式比朴素方法得到一些显着的加速。这使您可以快速为大型k
执行此操作。
我不知道是否有更有效、更近似的解决方案,这会很有趣。我想随机采样总会给你一些东西,但也许有某种光谱算法,基于矩阵M
或其他东西的奇异值分解。
注意:如果你真的想实现它,我想你不应该使用浮点数,矩阵M
实际上应该是整数矩阵。基本上,您将它乘以N
其中N
是字母表中的字母数。稍后您将跳过将总和乘以 N^k
。我认为使用概率更容易理解,但在那个版本中,M^k_{i,j}
只会计算number of paths from i to j of length k
.
注意:正如评论中指出的,对于任何固定的正则表达式,该算法的k
位数都是多项式的,因此即使对于大k
也很好。在最坏的情况下,尽管正则表达式的大小是指数级的——要处理大型和复杂的正则表达式,如果你想使用这种方法,你应该使用某种 DFA 最小化。对于问题中显示的简单正则表达式,我认为应该没问题。
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- 计算数组重复次数的组合的有效算法,加起来达到给定的总和
- 为 C++11 算法组合多个谓词
- 双重释放或损坏(输出):使用向量的组合算法0x0000000001a880a0***
- Python到C++:使用递归列出背包的所有组合的算法
- 从给定的 IPv6:端口列表中搜索 IPv6:端口组合的最快搜索算法是什么 O(1) 时间一致性
- 给定数字与重复的组合的算法?C
- 排列和组合生成算法
- 加密++对称算法和经过身份验证的块模式组合
- 所有的组合算法和解决C++问题的一般方法
- 按字典顺序打印给定字符串的所有字母组合的算法
- 生成每个可能的 7 位数字组合的算法
- 运行整数数组所有组合的算法
- 根据组合框中的选定项目选择算法
- C++算法优化:从N个元素中求出K组合
- 递归算法将所有组合分成两组
- 数组算法的组合
- 按类型算法的列表组合
- 一个很好的算法来获得元素的闲置组合
- 是硬币变化算法,输出仍可由DP解决的所有组合