将接受一组字符串的正则表达式A转换为接受A匹配的字符串的所有前缀的字符串

时间:2012-08-18 03:33:23

标签: regex

给定任何正则表达式A,是否有办法将其转换为正则表达式B,它接受A接受的字符串的所有字符串和前缀。

例如,如果/ apple /是给定的正则表达式,是否有一种通用的方法将其转换为/ a | ap | app | appl | apple /

3 个答案:

答案 0 :(得分:1)

如果您正在谈论formal regular expressions(即描述regular languages的正则表达式),那么这是一个将正则表达式转换为接受前缀的过程的过程。

任何正则表达式都有DFA;这是/apple/的DFA(转换为失败状态):

DFA for /apple/

要生成与此DFA接受的字符串前缀相匹配的DFA,如果它们位于导致接受原始DFA中的状态的路径中,则将状态转换为accepting states

DFA for prefixes of /apple/

several methods用于从DFA中读取正则表达式。如果我们使用状态删除技术,我们会得到以下DFA:

DFA for prefixes of /apple/, after state elimination

这对应于正则表达式/a|ap|app|appl|apple|/,加上空字符串(因为空字符串是任何正则表达式的前缀)。

apple示例很简单,但同样的技术可用于更复杂的正则表达式。例如,请考虑/(00)*1(00|1)*/

DFA for /(00)*1(00|1)*/

此DFA接受字符串00100但不接受0010101。在将适当的状态转换为最终状态并组合两个相同的状态后,我们有

Slightly minimized DFA for prefixes of /(00)*1(00|1)*/

这相当于

enter image description here

我们可以从中读取正则表达式/(00)*(0?|1(1|00)*0?)/,其中包含空字符串。

此正则表达式拒绝00101,因为它会导致原始DFA转换为失败状态,但接受“0”和“00”,因为这些字符串不会导致原始DFA进入失败状态。

答案 1 :(得分:0)

显然可以通过转换为有限状态机,将所有状态更改为接受状态,然后转换回来,如@JoshRosen 的回答所示。

这是一个更直接的算法。 为简单起见,我将假设正式定义 正则表达式 here。因此表达式是从空字符串、文字字符和运算符连接、交替 ('|') 和 Kleene 星形 ('*') 递归构建的。我还将包括运算符“?”,这样 A?(|A) 的缩写。

我们想定义一个转换 P,它接受任何正则表达式 A 并输出一个正则表达式 B=P(A),它完全接受 A 接受的前缀。 以下简单的 P 递归定义就可以做到:

P(empty string) = empty string
P(c) = c?   if c is a literal character
P(A?) = P(A)
P(A*) = (A* P(A))
P(A B) = (P(A) | (A P(B)))
P(A|B) = (P(A) | P(B))

正确性的证明当然是通过对正则表达式结构的归纳:观察它对于空字符串和文字字符是正确的, 并且,如果 AB 是正确的,那么 A BA|BA*A? 也是正确的。

我们还可以添加以下规则,这不是绝对必要的 但在文字字符串的常见情况下(即几个文字字符的串联)会导致更有效的输出表达式:

P(a B) = (a P(B))?  when a is a literal character

示例

考虑正则表达式 /abc/。通常我们不指定或不关心连接运算符是左关联还是右关联,因为结果接受的语言是相同的。但让我们通过两种方式解决它。

如果我们将串联视为从左到右的关联:

P(/abc/) = P((a b) c)
         = P(a b) | ((a b) P(c))
         = P(a b) | ((a b) c?)
         = (a P(b))? | ((a b) c?)
         = (a b?)? | ((a b) c?)
         = /(ab?)?|abc?/

或者,如果我们将串联视为从右到左关联,我们只需重复应用 P(a B) = (a P(B))? 规则即可获得更有效的(线性大小,doesn't repeat itself)输出:

P(/abc/) = P(a (b c))
         = (a P(b c))?
         = (a (b P(c))?)?
         = (a (b c?)?)?
         = /(a(bc?)?)?/

答案 2 :(得分:-2)

取决于广义方式的含义。

\b(a(p?(p?(l?(e?)))))\b

编辑:添加背后的正面看法代表了更好的解决方案,但它完全取决于正则表达式机器的实现。