没有重复数字的数字串的正则表达式?

时间:2011-09-24 13:13:24

标签: regex

我正在阅读dragon book并尝试解决以下所述的练习

  

为以下语言编写常规定义:

     
      
  • 没有重复数字的所有数字字符串。 提示:首先使用几位数来尝试此问题,例如{0,1,2}。
  •   

尽管已经试图解决它几个小时,我无法想象一个解决方案,除了极端罗嗦

d0 -> 0?
d1 -> 1?
d2 -> 2?
d3 -> 3?
d4 -> 4?
d5 -> 5?
d6 -> 6?
d7 -> 7?
d8 -> 8?
d9 -> 9?
d10 -> d0d1d2d3d4d5d6d7d8d9 | d0d1d2d3d4d5d6d7d9d8 | ...

因此必须在10!中编写d10个替代品。由于我们将这个常规定义,我怀疑这是一个正确的解决方案。你能帮帮我吗?

8 个答案:

答案 0 :(得分:11)

所以问题并不一定要求你写一个常规的表达式,它要求你提供一个常规的定义,我将其解释为包括NFA。事实证明,使用哪个并不重要,因为所有NFA都可以在数学上与正则表达式等效。

使用数字0,1和2,有效的NFA将如下(对于crummy图抱歉):

enter image description here

每个状态代表输入中扫描的最后一个数字,并且任何节点上都没有循环,因此这是一个字符串的精确表示,没有来自集合{0,1,2}的重复数字。扩展这是微不足道的(虽然它需要一个大的白板:))。

注意:我假设字符串“0102”有效,但字符串“0012”不是。

通过使用here描述的算法,可以将其转换为正则表达式(尽管会很痛苦)。

答案 1 :(得分:3)

这是一种可能的结构:

  • 包含最多一个'0'数字的字符串的正则表达式看起来像(1-9)*(0 | epsilon)(1-9)* - 所以任意数量的1-9位数,其次是零或1'0后跟任意数量的1-9位数。
  • 我们现在可以注意到,如果只有一个'1'数字,它将位于'0'数字的左侧或右侧(或代表缺失零位的epsilon)。因此,我们可以构造一个具有这两种情况的正则表达式或者'(|)在一起。
  • 我们现在可以进一步向下钻取说,如果只有一个'2'数字,它可以在1位数的右边或左边,它是两个可能的相对位置到'0'数字。
  • 所以我们正在构建一个二叉树,ORed正则表达式的数量大约为2 ^ 10,这与接受该语言的FSM的顺序相同。用于接受语言的FSM应该具有(2 ^ 10 + 1)个状态,每个状态n可以被视为它的二进制表示n0n1n2n3n4n5n6n7n8n9意味着n0 =看到数字'0',n1 =看到数字'1'。并且重复数字转换到单个非接受状态。初始状态为零。

如果允许补充,那么具有多个'0'数字的正则表达式将是(0-9)* 0(0-9)* 0(0-9)*,对所有数字重复,补充。

对于彼得泰勒的解释,没有两个连续的数字是相同的,你绝对可以更加紧凑。显然,这个问题的状态要小得多。

SUCCINCTNESS OF THE COMPLEMENT AND INTERSECTION OF REGULAR EXPRESSIONS

  

“[2]中的一项研究表明,大多数人都是明确的   在实践中使用的表达采用一种非常简单的形式:每个字母   符号最多出现一次。我们将这些称为单次出现   正则表达式(SOREs)并显示紧密的指数下限   交集。“

     

...

     

“在本节中,我们展示了在定义单个补码时   正则表达式,双指数大小增加不能   一般都避免了。相反,当表达式是   一个明确的补语可以用多项式时间计算。“

答案 2 :(得分:2)

而不是尝试编写仅定义所需内容的定义,如果您告诉它生成所有字符串列表,最多10位数字,包括重复项,然后再重复,那么该怎么办? 减去包含两个零,两个......等的?那会有用吗?

答案 3 :(得分:1)

(我不知道你指的是哪个正则表达式的变体,如果有的话,因此我将提供最常规形式的正则表达式的提示。)

我发现它是一个相当奇怪的正则表达式应用程序,因为这正是其中一个案例,它们并没有真正提供超过其他(更简单易懂的)解决方案的大好处。

但是,如果你绝对想要使用正则表达式,这里有一个提示(没有解决方案,因为它是一个练习,请告诉我你是否需要更多提示):

正则表达式可让您识别regular languages通常接受的 deterministic finite state machines 。尝试找到一个完全接受指定模式中的单词的状态机。它需要2^10 = 1024个州,但不需要10! = 3628800

答案 4 :(得分:1)

常规定义是表格

上的一系列定义

d1 - > R1

d2 - > R2

...

dn - > RN

现在进行以下定义:

零 - > 0

一个 - >零(1零)* | (零1)+ | 1(零1)* | (1个零)+

两个 - >一(2个)* | (一个2)+ | 2(一个2)* | (2个)+

三 - >两(3两)* | (两个3)+ | 3(2 3)* | (3二)+

四 - >三(4三)* | (三4)+ | 4(三4)* | (4三)+

...

九 - >八(9八)* | (8 9)+ | 9(8 9)* | (9八)+

答案 5 :(得分:0)

我从理论计算机科学的课程中记得:如果一个语言L是常规的,那么(不是L),即包含不在L中的所有单词的语言 - 这是否适合练习的背景?

答案 6 :(得分:0)

不确定你的问题标题中的“正则表达式”是什么意思。但如果正则表达式引擎支持负前瞻,这很容易实现。 (这是一个PHP代码段)

$re = '/# Match string of digits having no repeated digits.
    ^                 # Anchor to start of string.
    (?![^0]*0[^0]*0)  # Assert 0 does not occur twice.
    (?![^1]*1[^1]*1)  # Assert 1 does not occur twice.
    (?![^2]*2[^2]*2)  # Assert 2 does not occur twice.
    (?![^3]*3[^3]*3)  # Assert 3 does not occur twice.
    (?![^4]*4[^4]*4)  # Assert 4 does not occur twice.
    (?![^5]*5[^5]*5)  # Assert 5 does not occur twice.
    (?![^6]*6[^6]*6)  # Assert 6 does not occur twice.
    (?![^7]*7[^7]*7)  # Assert 7 does not occur twice.
    (?![^8]*8[^8]*8)  # Assert 8 does not occur twice.
    (?![^9]*9[^9]*9)  # Assert 9 does not occur twice.
    [0-9]+            # Match string of only digits.
    $                 # Anchor to end of string.
    /x';

答案 7 :(得分:0)

我认为没有一种简洁的方法来编写正则表达式来解决这个问题而不列出所有可能性。但我找到了一种方法,通过以下方式定义DFA,将复杂度从O(N!)降低到O(2 ^ N)。在我要构建的DFA中,状态表示是否出现任何数字。

以{0,1,2}组成的字符串为例,0表示'0'出现一次,0'表示'0'未出现。所有状态看起来都像{012,0'1'2',0'12,01'2,012',012',01'2,0'12}。总共会有2 ^ 3 = 8个状态。 DFA如下所示: DFA for strings with no repeating digits

您可以轻松地将其扩展到{0,1,2,...,9}。但总共会有1024个州。但是,我认为它是最紧凑的DFA,具有直观的证据。因为每个州都有独特的含义,不能进一步合并。