【问题标题】:Please help on some regular expressions [closed]请帮助一些正则表达式[关闭]
【发布时间】:2013-02-05 03:42:23
【问题描述】:

我在看龙书,被一些正则表达式练习卡住了,很有趣,有人能帮忙吗? 请为以下语言编写正则表达式:

问题1:
a's 和 b's 的所有字符串,其中 a's 偶数和 b's 奇数。

问题 2:
所有不包含子序列 abb 的字符串。 (s 的子序列是通过删除 s 的零个或多个不一定连续的位置形成的任何字符串。例如,baan 是香蕉的子序列。)

问题 3:
所有没有重复数字的数字字符串(重复数字不一定是连续的)。

问题 4:
最多包含一个重复数字的所有数字字符串(重复数字不一定是连续的)。

请使用 POSIX 语法,以便我们都能很好地理解它。另外我想知道我们是否只能使用三种基本的语言操作,即联合、连接和闭包来实现它们?

谢谢。

【问题讨论】:

  • 如果我回答所有四个问题,我会得到 4 倍的赞成票吗?我认为您应该提出更具体的问题,或者至少展示您的尝试。
  • 告诉我们您的尝试,我们可以帮助您。如果我们只是给你答案,你根本不会从中得到任何东西。如果您只是想看看它们是如何工作的,那么网上有很多示例正则表达式。
  • @ExplosionPills 那是5个问题:另外我想知道我们是否只能使用三种基本的语言操作,即联合、连接和闭包来实现它们?

标签: regex


【解决方案1】:

如果您有严格的正则表达式(连接、联合、闭包),您将能够将其转换为 POSIX 正则表达式。如果您有 POSIX 正则表达式,您将能够将其转换为任何更复杂的正则表达式引擎。

假设(请先阅读)

此答案假定 JavaScript 正则表达式的支持级别(具有前瞻但没有后瞻),但我们也假定 . 无一例外地匹配任何字符。此处的正则表达式将假定整个字符串与模式匹配。

问题 1

^(?=(?:b*ab*a)*b*$)(?=(?:a*ba*b)*a*ba*$)[ab]*$

可以为这个问题构造一个 DFA,因此,只有连接、联合和闭包的正则表达式存在。 (DFA 中状态的数字表示 a 和 b 的数量的奇偶性)。

然而,严格的正则表达式的推导相当混乱;环顾四周简化了我们的思维方式。

  • (?=(?:b*ab*a)*b*$) 是一个前瞻,(由于 ^$ 的影响)检查 whole 字符串是否匹配 (b*ab*a)*b* - 这意味着偶数个 a , b 在两者之间和周围是可选的和有限的。
  • (?=(?:a*ba*b)*a*ba*$) 是一个前瞻,检查 whole 字符串是否与 (a*ba*b)*a*ba* 匹配 - 这意味着 b 的奇数个,a 可选且有限多个介于两者之间和周围。

我们需要 3 次遍历字符串来检查字符串是否满足上述正则表达式的给定属性。

使用 POSIX 正则表达式,您可以针对这 2 个正则表达式测试一个字符串 2 次以断言 2 个属性:

^(b*ab*a)*b*$
^(a*ba*b)*a*ba*$

但由于存在严格的正则表达式并且可行,因此存在单个 POSIX 正则表达式来匹配满足属性的字符串。请阅读 this post 了解将 DFA 转换为严格正则表达式的方法。

问题 2

^(?!.*a.*b.*b).*$

只是向前看,检查没有办法匹配子序列abb

由于没有指定字母表,它可能被解释为任何和所有字符,用严格的正则表达式编写它是可能的,但不切实际。但是,如果允许否定字符类,则可以轻松编写:

([^a]*a[^b]*b[^b]*|[^a]*a[^b]*|[^a]*)

(上面是严格的正则表达式,但是可以很容易地改写为POSIX正则表达式)

交替的 3 项(从右到左)对应于 DFA 中的 3 个状态:尚未找到 a;前面有a,但没有b;后面有一个ab,但还没有找到第二个b。 DFA中还有一个陷阱状态(不可能转换到目标状态):找到了子序列abb

问题 3

^(?!\d*(\d)\d*\1)\d+$

使用负前瞻,我们将只检查是否没有匹配项可以找到重复的字符。由于这是一个数字字符串,因此我不允许通过指定至少 1 个数字 \d+ 来匹配空字符串。这个正则表达式的关键是使用捕获的组和反向引用。

同样,对此存在严格的正则表达式,但这是不切实际的,因为编写这样的正则表达式几乎等同于一一列出所有可能的匹配项。总共有 Sum [i = 1..10] ( 10! / i! ) 个可能的匹配项(允许前导 0)。没有办法绕过它,因为是否允许下一个字符在很大程度上取决于到目前为止已处理的所有字符。

这在 POSIX 正则表达式中也是不切实际的,因为没有否定捕获组的机制。

问题 4

无法为这个提供更好的正则表达式...

^(?!(?=.*(.).*\1).*((?!\1).).*\2)(?!.*(.)(?:.*\3){2})\d+$

失败有两种情况:数字重复超过 2 次,或者有 2 个不同的数字重复。

  • (?!(?=.*(.).*\1).*((?!\1).).*\2) 检查是否有 2 个不同的数字重复。由于((?!\1).),这种前瞻(?=.*(.).*\1) 挑选出一个重复的字符(至少两次),而.*((?!\1).).*\2 挑选出与之前检查的不同的数字,并尝试找到重复的数字。
  • (?!.*(.)(?:.*\3){2}) 检查一个数字最多重复两次。里面的模式尝试匹配一个数字的 3 个实例。

这与问题 3 有相同的问题,因此编写严格的正则表达式或 POSIX 正则表达式是不切实际的。如果您好奇,有Sum [i = 1..10] ( 10! / i! ) + Sum [i = 1..10] ( (i + 1)C2 * 10! / i! ) 可能的匹配项(允许前导 0)。


对于问题 3 和 4,尤其是问题 4,更实际的做法是检查字符串是否只包含数字,然后对数字进行排序并循环检查是否有重复的数字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    相关资源
    最近更新 更多