簡體   English   中英

將Backus-Naur形式語法轉換為.Net正則表達式

[英]Converting a Backus–Naur form grammar to a .Net regex

有沒有辦法將以下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 ">>"

我很接近,但我無法弄清楚如何處理逃避\\) 這將捕獲命名組中的fieldnameoption

<<(?<fieldname>.\*?)(\((?<option>.*?)\))?>>

編輯

事實證明,我對BNF語法比我想象的更生氣。

我試圖得到的是括號是特殊字符。 在“選項”部分中,它們必須通過斜杠進行轉義。 (還必須轉義斜線)。

BNF用於描述正則表達式通常無法描述的無上下文語言。 無上下文語言與正則表達式的區別在於無上下文語言可以同時在雙方進行遞歸。 一個典型的例子是平衡括號問題。

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')

正則表達式表示常規語言。 無上下文語法生成無上下文語言。 前一種語言集是后者的一個子集,在一般情況下,您不能將無上下文語言表達為正則表達式。

我一直在思考一個答案,並希望有人會跳我,所以我可以停下來。 :)

BNF的遞歸性質通常是一個很好的開放指標,如果你的問題很好地映射到BNF,它就不能很好地映射到RegExp。

我不得不承認,我不確定我是否能算出你的BNF。 例如:x :: = << Boo(abc321)>>

建議你的'選項'對是c3,b2和a1。 這假定char是一個有效的“選項” - 您沒有為不是空字符串的選項定義任何有效的終端值。 這真的是意圖嗎?

假設你不想被遞歸...處理轉義和其他一切......你可能只是更好地編寫代碼。 這看起來比通過其他任何東西更容易遍歷字符串和處理。 您想要的感覺表明您不需要任何前瞻或回顧邏輯。

我想我設法讓它發揮作用......

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

我能想到的訣竅是選項部分:

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

這意味着:雙斜線,斜線投球或非斜線投球。

然后將它包含0次或更多次並將其打到名為“option”的組中:

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

我還將fieldname更改為一個或多個非開放的parens:

fieldname =     [^\(]+

把它放在一起,我提出了解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM