Я разрабатываю многопоточный MIME-парсер, используя F # и FParsec. Я развиваюсь итеративно, и поэтому это очень нерафинированный, хрупкий код - он решает только мою первую проблему. Красный, Зеленый, Рефактор.F #, FParsec, и вызывать рекурсивный анализатор потока
Мне нужно разбирать поток, а не строку, которая действительно бросает меня за цикл. Учитывая это ограничение, насколько я понимаю, мне нужно вызвать рекурсивно парсер. Как это сделать, это за пределами моего кен, по крайней мере, с тем, как я продолжал до сих пор.
namespace MultipartMIMEParser
open FParsec
open System.IO
type private Post = { contentType : string
; boundary : string
; subtype : string
; content : string }
type MParser (s:Stream) =
let ($) f x = f x
let ascii = System.Text.Encoding.ASCII
let str cs = System.String.Concat (cs:char list)
let q = "\""
let qP = pstring q
let pSemicolon = pstring ";"
let manyNoDoubleQuote = many $ noneOf q
let enquoted = between qP qP manyNoDoubleQuote |>> str
let skip = skipStringCI
let pContentType = skip "content-type: "
>>. manyTill anyChar (attempt $ preturn() .>> pSemicolon)
|>> str
let pBoundary = skip " boundary=" >>. enquoted
let pSubtype = opt $ pSemicolon >>. skip " type=" >>. enquoted
let pContent = many anyChar |>> str // TODO: The content parser needs to recurse on the stream.
let pStream = pipe4 pContentType pBoundary pSubtype pContent
$ fun c b t s -> { contentType=c; boundary=b; subtype=t; content=s }
let result s = match runParserOnStream pStream() "" s ascii with
| Success (r,_,_) -> r
| Failure (e,_,_) -> failwith (sprintf "%A" e)
let r = result s
member p.ContentType = r.contentType
member p.Boundary = r.boundary
member p.ContentSubtype = r.subtype
member p.Content = r.content
Первая строка примера POST следующим образом:
content-type: Multipart/related; boundary="RN-Http-Body-Boundary"; type="multipart/related"
Она охватывает одну строку в файле. Дальнейшие части содержимого включают значения content-type
, которые охватывают несколько строк, поэтому я знаю, что мне придется уточнять свои парсеры, если я их повторно использую.
Как-то мне нужно позвонить pContent
с результатами (строки?) pBoundary
, чтобы я мог разделить остальную часть потока на соответствующих границах, а затем как-то вернуть несколько частей для содержимого сообщения, каждый из которых будет отдельный пост, с заголовками и контентом (который, очевидно, должен быть чем-то другим, кроме строки). Моя голова кружится. Этот код уже кажется слишком сложным для синтаксического анализа одной строки.
Большое значение для понимания и мудрости!
Я закончил с дискриминационным союзом, хотя я не уверен, что я хорошо его разработал. Я спросил [новый вопрос] (http://stackoverflow.com/questions/26891564/f-fparsec-and-calling-a-stream-parser-recursively-second-take) на основе этой обратной связи и отзывов от [мой второй вопрос] (http://stackoverflow.com/questions/26875192/f-fparsec-and-updating-userstate). Спасибо! –