代码之家  ›  专栏  ›  技术社区  ›  Adam Tegen

将BackusNaur表单语法转换为.Net正则表达式

  •  4
  • Adam Tegen  · 技术社区  · 17 年前

    <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语法方面比我想象的更粗糙。

    4 回复  |  直到 7 年前
        1
  •  8
  •   Markus Jarderot    17 年前

    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')
    
        2
  •  2
  •   user44511    17 年前

    正则表达式表示正则语言。上下文无关语法生成上下文无关语言。前一种语言集是后一种语言集的子集,在一般情况下,不能将上下文无关语言表示为正则表达式。

        3
  •  0
  •   Joe    17 年前

    我一直在思考一个答案,希望有人能跳过我,让我停下来。:)

    我必须承认,我甚至不确定我能不能算出你的BNF。例如:

    建议您的“选项”对为c3、b2和a1。这假设字符是有效的“选项”-您没有为不是空字符串的选项定义任何有效的终端值。这真的是目的吗?

    假设你不想被递归。。。 编写代码可能会更好。这看起来比其他任何事情都更容易处理。你想要什么的感觉表明你不需要任何向前看或向后看的逻辑。

        4
  •  0
  •   Adam Tegen    17 年前

    我想我成功地让它工作了。。。

    <<(?<fieldname>[^\(]+)(?<options>\((?<option>(\\\\|\\\)|[^\\\)])*)\))?>>
    

    我能想到的诀窍是选项部分:

    option =    (\\\\|\\\)||[^\\\)]
    

    转换为:双斜杠、斜杠paren或非斜杠paren字符。

    然后将其包含0次或多次,并将其放入名为“option”的组中:

    ((?<option>(\\\\|\\\)|[^\\\)])*)
    

    fieldname =     [^\(]+
    

    综合这些,我想出了解决办法。

    推荐文章