この質問を投稿した後、自分で解決策を導き出すことができたことに注意してください。私の最終的な答えについては、この質問の最後を参照してください。
現在、組織モードのドキュメント用の小さなパーサーに取り組んでいます。これらのドキュメントでは、見出しにタイトルを付けることができ、オプションで見出しのタグのリストで構成することもできます。
* Heading :foo:bar:baz:
ただし、このためのパーサーを作成するのは困難です。以下は、私が今のところ取り組んでいるものです。
import Control.Applicative
import Text.ParserCombinators.Parsec
data Node = Node String [String]
deriving (Show)
myTest = parse node "" "Some text here :tags:here:"
node = Node <$> (many1 anyChar) <*> tags
tags = (char ':') >> (sepEndBy1 (many1 alphaNum) (char ':'))
<?> "Tag list"
私の単純なパーサーは機能しますが、見出し ( ) のタイトルを解析するためにすべての文字が使い果たされるためtags
、 のコンテキストでは機能しません。さらに、このパーサーはタイトルで有効であるため、使用するように変更できません。実際、タグリストの行の最後にある場合にのみ特別です。node
many1 anyChar
noneOf ":"
:
このオプションのデータを解析する方法はありますか?
余談ですが、これは私の最初の実際の Haskell プロジェクトなので、Parsec がその仕事に適したツールでさえない場合は、遠慮なく指摘して他のオプションを提案してください。
わかりました、完全な解決策が得られましたが、リファクタリングが必要です。以下の作品:
import Control.Applicative hiding (many, optional, (<|>))
import Control.Monad
import Data.Char (isSpace)
import Text.ParserCombinators.Parsec
data Node = Node { level :: Int, keyword :: Maybe String, heading :: String, tags :: Maybe [String] }
deriving (Show)
parseNode = Node <$> level <*> (optionMaybe keyword) <*> name <*> (optionMaybe tags)
where level = length <$> many1 (char '*') <* space
keyword = (try (many1 upper <* space))
name = noneOf "\n" `manyTill` (eof <|> (lookAhead (try (tags *> eof))))
tags = char ':' *> many1 alphaNum `sepEndBy1` char ':'
myTest = parse parseNode "org-mode" "** Some : text here :tags: JUST KIDDING :tags:here:"
myTest2 = parse parseNode "org-mode" "* TODO Just a node"