【问题标题】:Simplify this regular expression简化这个正则表达式
【发布时间】:2026-02-25 07:50:02
【问题描述】:

我正在为我的编译器类做一些考前练习,并且需要简化这个正则表达式。

(a U b)*(a U e)b* U (a U b)*(b U e)a*

很明显,e 是空字符串,U 代表联合。

到目前为止,我认为可以删除 (a U b)* 之一,作为 a U a = a 的并集。但是,我找不到任何其他简化,到目前为止,我在其他问题上做得并不好。 :(

感谢任何帮助,非常感谢!

【问题讨论】:

  • 我更喜欢解释而不是任何答案,甚至是提示而不是答案,我正在做考前练习,没有解释的答案对我没有多大帮助!谢谢!
  • 我确实相信我接受的答案是错误的,正如 cmets 中所指出的那样。我确实认为结果确实是 (a U b)* 但我的解释不正确。

标签: regex simplify


【解决方案1】:

首先翻译成该语言的英文描述:

(a U b)*(a U e)b* U (a U b)*(b U e)a*

翻译为:


as 或bs 的任意序列,后跟可选的a,后跟任意数量的bs。

任意数量的as 和bs,后跟可选的b,后跟任意数量的as


这里有很多重叠 - 至少 (a U b)*(a U e)(a U b)* 完全相同,因为“as 和 bs 的任何序列”必然结束使用a 或 epsilon(因为任何字符串都可以以 epsilon 结尾),因此可以消除这些组,离开

(a U b)*b* U (a U b)*a*

翻译为:


as 或bs 的任意序列,后跟任意数量的bs。

任意数量的as 和bs,后跟任意数量的as


现在最外层组的第一部分是相同的,所以让我们将它们折叠成一个

(a U b)*(a* U b*)

翻译为:


as 或 bs 的任意序列,后跟任意数量的 as 或任意数量的 bs。


现在等一下,“A 和 B 的任何序列”必然以“as 的任何序列或bs 的任何序列”结尾,这意味着任何匹配第一部分可以匹配整个正则表达式(因为第二部分的长度可以为零)所以我们为什么不直接做呢

(a U b)*

达达。很简单。

【讨论】:

  • 根据你的推理, (a U b)*b 会以同样的方式减少......但事实并非如此。您必须确保不仅所有匹配项继续匹配,而且所有被拒绝的输入仍然被拒绝,并且您的论点错过了后者。
  • @Ben 哪一步丢失了信息?许多简化依赖于所有尾随位能够具有 0 长度,您的示例没有,所以我不确定您指的是什么。
  • @Ben,我 认为 你指的是我的第 1 步或第 3 步,我说这是因为第一次重复 必然 以我们的第二步结束可以删除第二个,这同样不适用于您的示例 - (a U b) 不一定b 结尾 - 它可能以 a 结尾,因此不适用简化。跨度>
【解决方案2】:

正则表达式有点生疏,但如果 * 仍然代表“零次或多次出现”,您可以替换:

(a U e)b* for (a U b)*

留下第一部分:

(a U b)*(a U b)* = (a U b)*

在右边,你有那个

(b U e)a* = (b U a)*

现在,由于 a U b = b U a,你得到:

(a U b)*(a U b)*

在右手边,只剩下

(a U b)* U (a U b)* = (a U b)*

我想就是这样……

【讨论】:

  • 天哪,我的头很痛,因为我的正则表达式也生锈了。您可能是对的,但是'e' 标记发生了什么?我不明白它是如何被淘汰的。但我可能看不到它(再次,年龄和缺乏咖啡以及正则表达式生锈。)
  • 第一步是错误的,因为前面只允许1个a并且只在第一个位置。
  • @BoltClock:我看到的答案中没有a?
  • @ben-voigt 我认为你是对的。 (a U e)b* = ab 不等价于 (a U b)*
  • 可以编辑答案吗?我认为正确的解释是 (a U b)*(a U e)b* U (a U b)*(b U e)a* = (a U b)*a?b* U (a U b )*b?a* = (a U b)* U (a U b)* = (a U b)* 哪里?是 0 或 1 次出现。
【解决方案3】:

我认为整个事情相当于(a U b)*(或在大多数正则表达式语法中,(a|b)*

【讨论】:

  • 因为我正在为考试做练习题,所以我更感兴趣的是你是如何得出这个结论的。你能分享一下吗?
  • 这是我的推理:查看顶部联合的左分支。一、取(a U b)*(a U e);通过联合分发连接以获得(a U b)*a U (a U b)*。第二部分是第一部分的超集,因此折叠成(a U b)*。将b* 添加到末尾执行相同的操作:与(a U b)*b* 匹配的任何内容也将与(a U b)* 匹配,反之亦然。这使得 RE 变成了(a U b)* U (a U b)*(b U e)a*;由于右侧只能接受ab的字符串,它是左侧的子集,所以RE简化为(a U b)*
  • @CompilersBeginner:两种形式是等价的,如果匹配第一个意味着匹配第二个,匹配第二个意味着匹配第一个,对吧?除了ab,你的表达式从不引入任何标记,所以任何匹配它的东西也匹配(a U b)*。任何(a U b)* 都与您的匹配,方法是采用第一个分支(a U b)*(a U e)b*,然后选择空字符串分支(a U b)* e b*,最后为b* 选择重复计数0。
【解决方案4】:

我会告诉你我将如何解决它:(不是很正式,也不能保证)

看主U的左边:

(a U b)* - 这是什么意思?长度为 n 的 a´s 和 b´s 的组合,其中 n >= 0。

接下来是(a U e)。我们有什么在这里?一个 a 或空词。如果我们想要它,我们可以在前面的部分中得到它。如果我们想要 e,那么无论如何我们都可以忽略它。请注意,我们不必选择 a,因为我们可以选择 e。所以我们可以跳过这整个部分。

接下来是什么?乙*。那是什么?我们想要多少 b 就多少。我们也可以在第一部分得到那些!我们可以忽略它!

所以左边唯一的就是 (a U b)*。

让我们看看右边:

好的,现在这很容易,我们可以使用相同的想法,只是不同的字母。

我们也会以同样的方式得到 (a U b)*。

所以最后我们有 (a U b)* U (a U b)* 你知道它等于 (a U b)*。

【讨论】:

  • 根据你的推理(a U b)*b 会以同样的方式减少......但事实并非如此。
  • 感谢您的提示,我试图在回答中提供一种不太正式的方法。我不确定如何在不放弃的情况下改进答案。