Я борюсь с Parsec
, чтобы разобрать небольшое подмножество Google project wiki syntax и преобразовать его в HTML. Мой синтаксис ограничен текстовыми последовательностями и списками элементов. Вот пример того, что я хочу, чтобы признать:Parsec, текст, заканчивающийся строкой
Text that can contain any kind of characters,
except the string "\n *"
* list item 1
* list item 2
End of list
Мой код до сих пор:
import Text.Blaze.Html5 (Html, toHtml)
import qualified Text.Blaze.Html5 as H
import Text.ParserCombinators.Parsec hiding (spaces)
parseList :: Parser Html
parseList = do
items <- many1 parseItem
return $ H.ul $ sequence_ items
parseItem :: Parser Html
parseItem = do
string "\n *"
item <- manyTill anyChar $
(try $ lookAhead $ string "\n *") <|>
(try $ string "\n\n")
return $ H.li $ toHtml item
parseText :: Parser Html
parseText = do
text <- manyTill anyChar $
(try $ lookAhead $ string "\n *") <|>
(eof >> (string ""))
return $ toHtml text
parseAll :: Parser Html
parseAll = do
l <- many (parseUl <|> parseText)
return $ H.html $ sequence_ l
При применении parseAll
в любой последовательности символов, я получаю следующее сообщение об ошибке: "*** Exception: Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string.
I что мой парсер parseText
может читать пустые строки, но я не вижу другого способа. Как распознать текст, ограниченный строкой? ("\n *"
здесь).
Я также открыт для любых замечаний или предложений относительно того, как я пользуюсь Parsec. Я не могу не видеть, что мой код немного уродлив. Могу ли я сделать все это проще? Например, существует репликация кода (что является болезненным) из-за строки "\n *"
, которая используется для распознавания конца текстовой последовательности, начала элемента списка и конца элемента списка ...
Does 'sepEndBy1 (string" * ">> many (noneOf" \ n ")) (строка" \ n ")' делать то, что вы хотите? Мне кажется, что язык, который вы описываете, это просто строка, содержащая множество строк, начинающихся с «*». В этом случае вам даже не нужен parsec: 'map (\ ('': '*': x) -> x). lines' – user2407038
Элемент списка может содержать символы новой строки и звезды, истинным разделителем для элементов списка является «\ n *». – eskaev
Единственными «незаконными» последовательностями являются строки, а не символы («\ n *» и «\ n \ n»). Вот почему noneOf не будет работать. И мне еще нужен способ разобрать текст, который может появиться перед списком. – eskaev