[英]Using PEG Parser for BBCode Parsing: pegjs or … what?
我有一個bbcode-> html轉換器,它響應textarea中的change事件。 當前,這是使用一系列正則表達式完成的,並且存在許多病理情況。 我一直想在這種語法上使鉛筆更鋒利,但又不想into牛刮胡。 但是...最近,我意識到了pegjs ,這似乎是PEG解析器生成的相當完整的實現。 我已經指定了大部分語法,但是現在想知道這是否適合使用成熟的解析器。
我的具體問題是:
由於我的應用程序依賴於將我可以轉換的內容轉換為HTML並將其余內容保留為原始文本,因此使用可能因語法錯誤而失敗的解析器實現bbcode有意義嗎? 例如:一旦輸入close標簽上的右括號, [url=/foo/bar]click me![/url]
當然會成功。 但是在此期間,用戶會看到什么? 使用正則表達式,我可以忽略不匹配的內容,並將其視為普通文本以進行預覽。 使用正式的語法,我不知道這是否可行,因為我依賴於從解析樹創建HTML,而解析失敗的原因是什么?
我不清楚應該在哪里進行轉換。 在基於lex / yacc的正式解析器中,我將具有表示節點類型的頭文件和符號。 在pegjs中,我得到帶有節點文本的嵌套數組。 我可以將翻譯后的代碼作為由pegjs生成的解析器的操作來發出,但是將解析器和發射器結合起來似乎具有代碼味道。 但是,如果我調用PEG.parse.parse()
, PEG.parse.parse()
得到類似以下的內容:
[
[
"[",
"img",
"",
[
"/",
"f",
"o",
"o",
"/",
"b",
"a",
"r"
],
"",
"]"
],
[
"[/",
"img",
"]"
]
]
給出如下語法:
document
= (open_tag / close_tag / new_line / text)*
open_tag
= ("[" tag_name "="? tag_data? tag_attributes? "]")
close_tag
= ("[/" tag_name "]")
text
= non_tag+
non_tag
= [\n\[\]]
new_line
= ("\r\n" / "\n")
當然,我在縮寫語法,但是您明白了。 因此,如果您注意到,在數組數組中沒有上下文信息可以告訴我我擁有哪種節點,即使認為解析器已經做到了,我仍然可以再次進行字符串比較。 我希望可以在解析期間定義回調並使用操作來運行它們,但是Web上很少有關於如何做的信息。
我在樹上叫錯了嗎? 我應該退回到正則表達式掃描而忘記解析嗎?
謝謝
第一個問題 (不完整文本的語法):
你可以加
incomplete_tag = ("[" tag_name "="? tag_data? tag_attributes?)
// the closing bracket is omitted ---^
在 open_tag
之后 ,並將document
更改為在末尾包含不完整的標簽。 訣竅在於,您為解析器提供了所有需要進行生產的產品,以始終進行分析,但是有效的產品優先。 然后,您可以在實時預覽期間忽略incomplete_tag
。
第二個問題 (如何包括動作):
您在表達式后編寫所謂的動作 。 動作是用大括號括起來的Javascript代碼,並且可以在pegjs表達式之后(即,在生產過程中)使用它!
在實踐中,幾乎總是需要諸如{ return result.join("") }
類的動作,因為pegjs會分成單個字符。 還可以返回復雜的嵌套數組。 因此,我通常在語法的開頭的pegjs初始值設定項中編寫幫助程序函數,以保持較小的動作。 如果您仔細選擇函數名稱,則該操作是自記錄的。
例如,請參見PEG for Python樣式縮進 。 免責聲明:這是我的回答。
關於第一個問題,我不得不說實時預覽將很困難。 您指出的有關解析器無法理解輸入為“進行中的工作”的問題是正確的。 Peg.js會告訴您錯誤發生在哪一點,因此也許您可以獲取該信息並返回幾句話以再次解析,或者如果缺少結束標記,請嘗試在最后添加它。
問題的第二部分比較簡單,但是之后語法就不會那么好了。 基本上,您要做的是在每個規則上都放置回調,例如
text
= text:non_tag+ {
// we captured the text in an array and can manipulate it now
return text.join("");
}
目前,您必須在語法中內聯編寫這些回調。 我現在正在做很多這樣的事情,因此我可能會對peg.js提出pullrequest來解決此問題。 但是我不確定何時有時間這樣做。
嘗試類似此替換規則的操作。 您走在正確的軌道上; 您只需要告訴它來組合結果即可。
文字=結果:non_tag + {返回result.join(''); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.