输入是表示元素列表的字符串。
列表定义为开放式卷曲{
,后跟0个或更多元素,用空格分隔后跟闭合卷曲}
。
元素是文字或元素列表。
文字是一系列非空白字符。如果元素包含大括号,则必须使用反斜杠对其进行转义:\{
和\}
。 (或者你可以假设文字中不允许使用curlies,为简单起见)
示例:
"{abc { def ghi } 7 { 1 {2} {3 4} } {5 6} x\{yz \}foo }"
文字中没有curlies:
"{abc { def ghi } 7 { 1 {2} {3 4} } {5 6} xyz foo }"
(这是Tcl列表的简化定义。)
我想知道的是:可以使用正则表达式将输入拆分为最外层循环的元素吗?
预期产出:
abc
{ def ghi }
7
{ 1 {2} {3 4} }
{5 6}
x{yz
}foo
真正的问题是:这可以用正则表达式完成吗?
我对.NET风格最感兴趣,但会接受任何答案。
我会在答案中发布自己的假设,看看它是否经过验证或销毁。
答案 0 :(得分:4)
不幸的是,对于Regex的某些风格,答案是肯定的,例如PCRE和.NET因为它们分别支持递归模式和类似堆栈的操作。
语法可以写成
ELEMENT -> (?!\{)\S+ | LIST
LIST -> '\{\s*' ELEMENT? ('\s+' ELEMENT)* '\s*\}'
因此在PCRE中,这可以转换为模式:
\{\s*(?0)?(?:\s+(?0))*\s*\}|(?!\{)(?:[^\s}]|\}(?![\s}]))+
# --------------------------- ^^^^^^^^^
# LIST Make sure the } is not closing the group
例如,请参阅http://www.ideone.com/SnGsU(为简单起见,我已删除了顶级{
和}
。
(当然,不要在工作中尝试这个:))
(顺便说一句,我不知道如何将这个PCRE转换成.NET风格。如果有人知道,请尝试Converting PCRE recursive regex pattern to .NET balancing groups definition)
答案 1 :(得分:3)
好吧,编辑从标记中移除花括号并从问题中获取刺痛,现在使用平衡组很容易使用.Net Regexes。它只是匹配括号,这是一个基本的例子
就像KennyTM的回答一样,这只有在你移除顶级支架时才有效,或者它会与整个输入相匹配。
同样,这更适合用于娱乐目的:
(?: # try matching...
(?:\\[{}]|[^\s{}])+\s*? # a literal (allow escaped curly braces)
| # OR
(?<Curly>{)\s* # "{" and push to stack
| # OR
(?<-Curly>})\s*? # "}", pop from stack and fail if the stack is empty
)+? # ...a few times, and stop whenever you can.
(?(Curly)(?!)) # Make sure there aren't any extra open curly braces
有关详细信息,请参阅此文章:Regex Balancing Group in Depth
答案 2 :(得分:2)
对此的传统答案是响亮的“不”。正如我们在编译器类中学到的那样,常规语法不能用于描述具有递归定义的语言(即,您不能使用有限状态机)
答案 3 :(得分:1)
@Cristi关于正则表达式是正确的:理论上不可能使用无堆栈的有限状态自动机来解决递归表达式。 但是,解决方案更简单:您只需要保持打开括号数量的计数器,并确保它不会低于0.它比维护堆栈节省更多内存,而您只需要计数 - 而不是圆括号的内容。
算法:
counter = 0 // Number of open parens
For char c in string:
print c
if c=='{': // Keep track on number of open parens
counter++
if c=='}':
counter--
if counter==1: // New line if we're back to the top level
print "\n"
elif counter<1: // Error if the nesting is malformed
print "ERROR: parentheses mismatch"
break