我需要运行以下测试: 如果一个表达式包含'{',那么只有在找到另一个'}时才接受表达式 有效的表达式是'aaa {aaa} aaa','{aa}','a {aa {aa} aa} aa','{a {a} a}'等...... 我怎么能这样做?
如果重要,我将在XSD文档中运行此测试...
答案 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的表示法表达:
<S> ::= <empty> | <S> a | <S> { <S> } .
<empty> ::= .
或者,在扩展的BNF中:
S ::= (a|{S})*
然后我们可以通过这种方式重写它以跟踪嵌套(以词缀语法的方式):
S ::= (a|{S1})*
S1 ::= (a|{S2})*
S2 ::= (a|{S3})*
etc.
在选定的级别 n ,我们可以通过这种方式结束递归(从而使语言成为常规):
Sn ::= a*
然后我们可以通过一次替换一个级别来构建正则表达式:
S = (a|{S1})*
= (a|{(a|{S2})*})*
= (a|{(a|{(a|{S3})*})*})*
etc.
在这种情况下,归结为:为了深入嵌套 n 级别,我们从 n 字符串“(a|{
”的副本开始,继续使用“a*
”,并以 n 字符串“})*
”的副本结束。要允许a
以外的字符,我们可以使用[^{}]
而不是a
重写。
如果我们用四级嵌套大括号停止替换,我们得到表达式
([^{}]|{([^{}]|{([^{}]|{([^{}]|{[^{}]*})*})*})*})*
如果重要的是没有法律表达被拒绝,我们可以将中心[^{}]*
替换为.*
或(.|\n)*
,将其转换为超集表达式;然后我们有一个正则表达式,它接受(a)具有正确嵌套大括号不超过四个字符串的字符串,以及(b)具有嵌套四个深度的大括号的字符串,包含最内层的任意字符串(所以第五个,第六个或第n个)嵌套水平不一定正确)。
([^{}]|{([^{}]|{([^{}]|{([^{}]|{[(.|\n)*})*})*})*})*
相比之下,重要的是不要接受任何非法表达,最好坚持使用子集表达式。