正则表达式如何进行以下测试:如果表达式包含'{',那么只有在找到另一个'}'时才接受表达式?

时间:2012-10-05 12:12:33

标签: regex xsd

我需要运行以下测试: 如果一个表达式包含'{',那么只有在找到另一个'}时才接受表达式 有效的表达式是'aaa {aaa} aaa','{aa}','a {aa {aa} aa} aa','{a {a} a}'等...... 我怎么能这样做?

如果重要,我将在XSD文档中运行此测试...

2 个答案:

答案 0 :(得分:2)

您所描述的语言(与Dyck语言密切相关)是无上下文的,不是常规的(Chomsky层次结构中的类型2)。也就是说,基本正则表达式不可能用于构造这种语言的接受者。

但是,堆栈计算机可以为您描述的语言类型决定单词问题。要实现这一点,您应该将String标记为字符,迭代每个字符,如果发现左括号,则将计数器初始化为0。如果您发现右括号将其减1。如果在整个执行过程中保持不变counter >= 0并且计数器的最终状态为0,则接受该单词。

答案 1 :(得分:1)

由于MichaelSchmeißer概述的原因,XSD正则表达式无法识别问题中描述的语言。 (它可能被Perl兼容的模式识别,这些模式早已让3类语言落后,但XSD不使用反向引用和其他赋予Perl表达式额外功能的设备。)

常规近似值

您对MS的回答的评论表明您可能愿意接受对问题中​​描述的语言的常规近似。如果是这样,那么你可以选择常规子集语言,它只接受原始语言的单词,但可能会错误地拒绝其中的一些,或者是一种常规的超集语言,它接受语言的所有单词但错误地接受一些非语言。也是这样的话。

评论中的近似值

MS答案评论中给出的表达式是一个常规子集。它有三个明显的局限性:

  • 它允许大括号最多嵌套三个深。
  • 至少需要一对大括号(它不接受字符串“aaa”)。
  • 在每个嵌套级别最多允许一对括号(它不接受“a{a}a{a}a”)。

像第一个这样的限制是不可避免的;您可以选择一个高于三的数字,但在常规子集中始终存在最大嵌套深度。然而,另外两个并不是必需的,可以通过子集表达式的系统开发来避免。

系统地开发子集表达式

从BNF开始

为简单起见,在原始帖子中说明的语言,我们可以用类似BNF的表示法表达:

<S> ::= <empty> | <S> a | <S> { <S> } .
<empty> ::= .

或者,在扩展的BNF中:

S ::= (a|{S})*

重写以使嵌套级别显式

然后我们可以通过这种方式重写它以跟踪嵌套(以词缀语法的方式):

S ::= (a|{S1})*
S1 ::= (a|{S2})*
S2 ::= (a|{S3})*
etc.

在选定的级别 n ,我们可以通过这种方式结束递归(从而使语言成为常规):

Sn ::= a*

用LHS代替RHS

然后我们可以通过一次替换一个级别来构建正则表达式:

S = (a|{S1})*
  = (a|{(a|{S2})*})*
  = (a|{(a|{(a|{S3})*})*})*
etc.

在这种情况下,归结为:为了深入嵌套 n 级别,我们从 n 字符串“(a|{”的副本开始,继续使用“a*”,并以 n 字符串“})*”的副本结束。要允许a以外的字符,我们可以使用[^{}]而不是a重写。

n = 4

的结果

如果我们用四级嵌套大括号停止替换,我们得到表达式

([^{}]|{([^{}]|{([^{}]|{([^{}]|{[^{}]*})*})*})*})*

超集表达式作为替代

如果重要的是没有法律表达被拒绝,我们可以将中心[^{}]*替换为.*(.|\n)*,将其转换为超集表达式;然后我们有一个正则表达式,它接受(a)具有正确嵌套大括号不超过四个字符串的字符串,以及(b)具有嵌套四个深度的大括号的字符串,包含最内层的任意字符串(所以第五个,第六个或第n个)嵌套水平不一定正确)。

([^{}]|{([^{}]|{([^{}]|{([^{}]|{[(.|\n)*})*})*})*})*

相比之下,重要的是不要接受任何非法表达,最好坚持使用子集表达式。