是否可以将以下Backus–Naur形式(BNF)语法转换为.Net正则表达式? (我并不拘泥于BNF,但我认为这可能是解释我正在尝试做的最好的方法)。
<field> ::= "<<" <fieldname> <options> ">>"
<options> ::= "" | "(" <option> ")"
<option> ::= "" |
<option> <non-paren> |
<option> <escaped-character>
<escaped-character> ::= "\\" | "\)"
<non-paren> ::= any character but paren
<fieldname> ::= any string that doesn't contain "(" or ">>"
我已经接近了,但是我不知道如何处理转义的
\
和)
。这将捕获命名组中的fieldname
和option
:<<(?<fieldname>.\*?)(\((?<option>.*?)\))?>>
编辑
事实证明,我对BNF语法的怀疑比我想象的要生锈。
我想知道的是括号是特殊字符。在“选项”部分中,必须用斜杠将其转义。 (并且也必须转义斜线)。
最佳答案
BNF用于描述无上下文语言,而regex通常无法描述这种语言。区分上下文无关的语言和正则表达式的是,上下文无关的语言可以同时在两侧进行递归。一个经典的例子是平衡括号问题。
paren = paren paren
| '(' paren ')' <-- there are characters on both sides of the recursion
| ''
在您的情况下,您不使用任何双面递归,因此可以简化为常规语言。
fieldname = /(?:>?[^(>])+/ //No double >, but single ones are ok.
option = /(?:[^()\\]|\\.)*/ //No parens, unless preceeded by \
pattern = /<<(?<fieldname> )(?:\((?<option> )\))?>>/
把它放在一起:
pattern = /<<(?<fieldname>(?:>?[^(>])+)(?:\((?<option>(?:[^()\\]|\\.)*)\))?>>/
一些边境案件:
<<f>oo(bar>>)>> --> ('f>oo', 'bar>>')
<<foo(bar\))>> --> ('foo', 'bar\)')
<<foo(bar\\)>> --> ('foo', 'bar\\')
<<foo\(bar)>> --> ('foo\', 'bar')
编辑:
如果要在
<<
和>>
中转义任何多余的括号字符(和反斜杠),可以执行以下操作:fieldname = /(?:<?[^()\\<]|<?\\[()\\])+/
options = /(?:[^()\\]|\\[()\\])*/
pattern = /<<(?<fieldname> )(?:\((?<option> )\))?>>/
/<<(?<fieldname>(?:<?[^()\\]|<?\\[()\\])+)(?:\((?<option>(?:[^()\\]|\\[()\\])*)\))?>>/
更新:
<<f>oo(bar>>)>> --> ('f>oo', 'bar>>')
<<foo(bar\))>> --> ('foo', 'bar\)')
<<foo(bar\\)>> --> ('foo', 'bar\\')
<<foo\(bar)>> --> doesn't match
<<foo\((bar)>> --> ('foo\(', 'bar')