Tôi có ngôn ngữ đánh dấu tương tự như đánh dấu và ngôn ngữ được SO sử dụng.Thực hiện phân tích cú pháp cho ngôn ngữ giống như đánh dấu
Trình phân tích cú pháp cũ dựa trên regex và hoàn toàn là cơn ác mộng để duy trì, vì vậy tôi đã đưa ra giải pháp của riêng mình dựa trên ngữ pháp EBNF và được triển khai thông qua mxTextTools/SimpleParse.
Tuy nhiên, có vấn đề với một số mã thông báo có thể bao gồm nhau và tôi không thấy cách 'thực hiện'.
Dưới đây là một phần của ngữ pháp của tôi:
newline := "\r\n"/"\n"/"\r"
indent := ("\r\n"/"\n"/"\r"), [ \t]
number := [0-9]+
whitespace := [ \t]+
symbol_mark := [*_>#`%]
symbol_mark_noa := [_>#`%]
symbol_mark_nou := [*>#`%]
symbol_mark_nop := [*_>#`]
punctuation := [\(\)\,\.\!\?]
noaccent_code := -(newline/'`')+
accent_code := -(newline/'``')+
symbol := -(whitespace/newline)
text := -newline+
safe_text := -(newline/whitespace/[*_>#`]/'%%'/punctuation)+/whitespace
link := 'http'/'ftp', 's'?, '://', (-[ \t\r\n<>`^'"*\,\.\!\?]/([,\.\?],?-[ \t\r\n<>`^'"*]))+
strikedout := -[ \t\r\n*_>#`^]+
ctrlw := '^W'+
ctrlh := '^H'+
strikeout := (strikedout, (whitespace, strikedout)*, ctrlw)/(strikedout, ctrlh)
strong := ('**', (inline_nostrong/symbol), (inline_safe_nostrong/symbol_mark_noa)* , '**')/('__' , (inline_nostrong/symbol), (inline_safe_nostrong/symbol_mark_nou)*, '__')
emphasis := ('*',?-'*', (inline_noast/symbol), (inline_safe_noast/symbol_mark_noa)*, '*')/('_',?-'_', (inline_nound/symbol), (inline_safe_nound/symbol_mark_nou)*, '_')
inline_code := ('`' , noaccent_code , '`')/('``' , accent_code , '``')
inline_spoiler := ('%%', (inline_nospoiler/symbol), (inline_safe_nop/symbol_mark_nop)*, '%%')
inline := (inline_code/inline_spoiler/strikeout/strong/emphasis/link)
inline_nostrong := (?-('**'/'__'),(inline_code/reference/signature/inline_spoiler/strikeout/emphasis/link))
inline_nospoiler := (?-'%%',(inline_code/emphasis/strikeout/emphasis/link))
inline_noast := (?-'*',(inline_code/inline_spoiler/strikeout/strong/link))
inline_nound := (?-'_',(inline_code/inline_spoiler/strikeout/strong/link))
inline_safe := (inline_code/inline_spoiler/strikeout/strong/emphasis/link/safe_text/punctuation)+
inline_safe_nostrong := (?-('**'/'__'),(inline_code/inline_spoiler/strikeout/emphasis/link/safe_text/punctuation))+
inline_safe_noast := (?-'*',(inline_code/inline_spoiler/strikeout/strong/link/safe_text/punctuation))+
inline_safe_nound := (?-'_',(inline_code/inline_spoiler/strikeout/strong/link/safe_text/punctuation))+
inline_safe_nop := (?-'%%',(inline_code/emphasis/strikeout/strong/link/safe_text/punctuation))+
inline_full := (inline_code/inline_spoiler/strikeout/strong/emphasis/link/safe_text/punctuation/symbol_mark/text)+
line := newline, ?-[ \t], inline_full?
sub_cite := whitespace?, ?-reference, '>'
cite := newline, whitespace?, '>', sub_cite*, inline_full?
code := newline, [ \t], [ \t], [ \t], [ \t], text
block_cite := cite+
block_code := code+
all := (block_cite/block_code/line/code)+
Vấn đề đầu tiên là, spoiler, mạnh mẽ và nhấn mạnh có thể bao gồm nhau theo thứ tự tùy ý. Và có khả năng là sau này tôi sẽ cần thêm nhiều đánh dấu nội tuyến như vậy.
Giải pháp hiện tại của tôi liên quan đến việc tạo mã thông báo riêng biệt cho từng kết hợp (inline_noast, inline_nostrong, v.v.), nhưng rõ ràng, số lượng kết hợp như vậy tăng quá nhanh với số yếu tố đánh dấu ngày càng tăng.
Vấn đề thứ hai là những vẻ ngoài mạnh mẽ/nhấn mạnh này hoạt động kém trên một số trường hợp đánh dấu kém như __._.__*__.__...___._.____.__**___***
(nhiều ký hiệu đánh dấu được đặt ngẫu nhiên). Phải mất vài phút để phân tích cú pháp vài kb của văn bản ngẫu nhiên như vậy.
Có vấn đề gì với ngữ pháp của tôi hay tôi nên sử dụng một số loại trình phân tích cú pháp khác cho tác vụ này?
[cletus] (http://stackoverflow.com/users/18393/cletus) có một chuỗi dài các bài đăng mô tả công việc của mình về phân tích cú pháp Markdown [trên blog của anh ấy] (http://www.cforcoding.com/search/label/markdown). Họ có các tiêu đề như "Markdown, Block Parsing và Road to Hell". Bạn có thể tìm thấy một số thông tin hoặc thông tin chi tiết có liên quan tại đó. –
hãy xem [PyParsing] (http://pyparsing.wikispaces.com/) – leoluk
@Greg Thats thú vị, cảm ơn bạn đã chia sẻ. Tuy nhiên có vẻ như anh ta cũng không giải quyết đánh dấu nội tuyến, và tôi không có vấn đề gì với việc đánh dấu khối. –