【问题标题】:What are the type of Strings generated by (a*+b*)(a*+b*) 生成的字符串有哪些类型
【发布时间】:2016-03-18 09:09:32
【问题描述】:

除了 aa.. 或 bb.. 之类的任意数量的 a 和 b 的字符串之外,正则表达式 (a*+b*) 是否会包含类似

的字符串

ab

或任何以 b 结尾的字符串?

(a*+b*) 和 (a* b*) 一样吗?

我对正则表达式 (a*+b*) 生成的字符串有点困惑,如果有人能提供帮助,我将不胜感激。

【问题讨论】:

  • 抱歉,我不认为 a*+ 是有效的正则表达式,也不是计算理论中的语言表达式(抱歉,我只在大学上过一个关于这个主题的学位课程)。如果你想要一个表示一个或多个'a',后跟一个或多个'b',它应该是a+b+。如果只允许 'a' 不带 'b' 并且只允许 'b' 不带 'a',甚至是一个空字符串,它将是 ab。所以...
  • *+ 是一个占有欲贪心量词。玩得开心:regular-expressions.info/possessive.html
  • 感谢您的阅读,对我来说非常新。我完全基于 FA 的概念使用正则表达式。
  • @hek2mgl:您的解释可能是正确的,但我怀疑 OP 使用的是正式语言教科书,+ 被用作常见的析取运算符(“或”)在数学中。
  • 如果它的a* b* 等效表达式是a*|b*。如果这是唯一的表达式,它将匹配所有a 或所有b 的子字符串,但不能同时匹配两者。如果它的a*b* 与另一个具有相同的影响,则可能会混合使用ab。这个表达式a*+b* 作为一个正则表达式使用了一个稍微复杂的运算符,其中+ 是一个量词的修饰符。在这种情况下,它告诉引擎的回溯部分在匹配后不返回任何a。这是一个高级主题,可能不是您想要的。

标签: regex compiler-construction computation-theory


【解决方案1】:

除非您使用的正则表达式语言将*+ 明确分类为具有特殊含义或保留用于未来扩展(现在产生定义的行为或语法错误)的特殊标记,否则a*+的自然解析是它意味着(a*)+:后缀+应用于表达式a*

如果该解释适用,接下来我们可以观察到 (a*)+ 仅等同于 a*。因此a*+b*a*b* 相同。

首先,根据定义R+ 表示RR*。匹配一个R,然后匹配零个或多个。因此,我们可以将(a*)+重写为(a*)(a*)*

其次,* 是幂等的,所以(a*)* 就是(a*)。如果我们匹配“零次或多次a”,零次或多次,没有任何变化;净效应为零或更多a证明: R* 表示这个无限扩展:(|R|RR|RRR|RRRR|RRRRR|...):不匹配,或者匹配一个R,或者匹配两个R,...因此,(a*)* 证明了这个扩展:(|a*|a*a*|a*a*a*|...)。这些内部a*-s 依次表示各个二级扩展:(|(|a|aa|aaa|...|)|(|a|aa|aaa|...)(a|a|aaa|...))|...)。通过分支| 的关联属性,我们可以将(a|(b|c)) 之类的结构展平为(a|b|c),当我们对扩展执行此操作时,我们注意到有许多相同的术语——空正则表达式(),单a,双aa等等。这些都简化为一个副本,因为(|||) 相当于()(a|a|a|a|...) 相当于只是(a) 等等。也就是说,当我们通过增加长度对术语进行排序,并将多个相同的术语压缩为一个副本时,我们最终得到(|a|aa|aaa|aaaa|...),这可以识别为a*的扩展。因此(a*)*a*

最后,(a*)(a*) 仅表示a*证明: 与前面类似,我们扩展为分支:(|a|aa|aaa|...)(|a|aa|aaa|...)。接下来,我们注意到分支表达式的串联等效于项的笛卡尔积集。也就是说,(a|b|c|..)(i|j|k|...) 的意思是:(ai|aj|ik|...|bi|bj|bk|...|ci|cj|ck|...|...)。当我们将此产品应用于(|a|aa|aaa|...)(|a|aa|aaa|...) 时,我们会得到大量的术语,当它们以增加的长度排列并进行重复数据删除时,会减少到(|a|aa|aaa|aaaa|...),这就是a*

【讨论】:

    【解决方案2】:

    我认为在这里查看正则表达式的正式定义会有所帮助,即查找每个正则表达式 e 它产生哪种语言 L(e)。

    让我们从简单的开始:

    (1) 那么正则表达式 a (只有字母)呢?它的语言是

     L(a) := {a},
    

    只有一个单词/字符“a”。

    (2) 对于正则表达式 e1 + e2,其中 e1 和 e2 本身就是正则表达式,

    L(e1 + e2) := L(e1) U L(e2).
    

    例如如果 a 和 b 是字符,L(a+b) = {a, b}。

    (3) 对于正则表达式 e1 e2(连接),其中 e1 和 e2 本身就是正则表达式,

    L(e1 e2) := all words w such that 
    we can write w = w_1w_2 with w_1 in L(e1) and w_2 in L(e2)".
    

    (4) 那么正则表达式 *e** 呢,其中 e 可能是正则表达式本身?直观地说,如果一个词具有以下形式,则它在 L(e*) 中 w_1 w_2w_3w_4...w_n,每个 i 在 L(e) 中都有 w_i。 所以

    L(e*) := all words w such that we can write 
             w = w_1 w_2 .. w_n 
               for a n >= 0 with all w_i in L(e) (for i = 1, 2, ..., n)
    

    那么,L((a* + b*)) 呢?

    L((a* + b*)) 
    (according to rule 2)
    = L(a*) U L(b*)
    (according to rule 4/1)
    = {eps, a, aa, aaa, aaaa, ....} U {eps, b, bb, bbb, bbbb}
    = all strings that have either only a's OR only b's in it 
      (including eps, the so-called empty word)
    

    同样适用于 (a* b*):

     L((a* b*))
     (according to rule 3)
     = all words w = w_1 w_2 with w_1 in L(a*) and w_2 in L(b*)
     = {eps eps, eps b, a eps, ab, aa eps, aab, ...}
     = {eps, b, a, ab, aa, aab, aabb, ... }
     = all strings that first have zero or more a's, then zero or more b's.
    

    一开始我认为它有助于“解构”正则表达式,就像我们在上面所做的那样 - 因为正则表达式也可以被视为树,就像更知名的算术表达式一样,例如:

        +
      /   \
     *     *
     |     |
     a     b
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-18
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      相关资源
      最近更新 更多