【问题标题】:Parsing text with optional data at the end最后解析带有可选数据的文本
【发布时间】:2011-02-17 00:14:28
【问题描述】:

请注意,在发布此问题后,我自己设法得出了一个解决方案。我的最终答案见本题结尾。


我目前正在为org-mode 文档开发一个小解析器,在这些文档中,标题可以有一个标题,并且可以选择包含标题的标签列表:

* 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 ":",因为: 在标题中有效。事实上,它只有在 taglist 中,在行尾才是特别的。

有什么想法可以解析这些可选数据吗?

顺便说一句,这是我第一个真正的 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"

【问题讨论】:

  • 先将标头解析为 lit 然后将数据编组到结构中怎么样?
  • 嗨,我不知道什么是“点亮”,但我仍然不明白如何在不使用标签部分的情况下解析标题并忽略标签在我的解析器中
  • 嗨@ocharles,生成的组织模式解析器真的存在吗,你分享代码吗?我开始深入研究 haskell,将这种学习与 org-mode 修补相结合在某种程度上是一个令人愉快的想法。亲切的问候,
  • @TomRegner - 不是特别的,虽然在我的 GitHub 上有一些工作:github.com/ocharles

标签: parsing haskell parsec


【解决方案1】:
import Control.Applicative hiding (many, optional, (<|>))
import Control.Monad
import Text.ParserCombinators.Parsec

instance Applicative (GenParser s a) where
  pure = return
  (<*>) = ap

data Node = Node { name :: String, tags :: Maybe [String] }
  deriving (Show)

parseNode = Node <$> name <*> tags
  where tags = optionMaybe $ optional (string " :") *> many (noneOf ":\n") `sepEndBy` (char ':')
        name = noneOf "\n" `manyTill` try (string " :" <|> string "\n")

myTest = parse parseNode "" "Some:text here :tags:here:"
myTest2 = parse parseNode "" "Sometext here :tags:here:"

结果:

*Main> myTest
Right (Node {name = "Some:text here", tags = Just ["tags","here",""]})
*Main> myTest2
Right (Node {name = "Sometext here", tags = Just ["tags","here",""]})

【讨论】:

  • 看起来不错,但我似乎无法在我的 GHCI 中加载它:`Applicative (GenParser s a)' 的非法实例声明。我可以通过完全删除 Application 实例来解决这个问题。但是,它仍然存在“标题:更多文本:标签:此处:”无法解析的问题 :(
  • 这看起来很不错,但你能解释一下你到底在做什么吗?
  • @ocharles 不会直接粘贴到 ghci - 它无法处理某些语法。保存到 foo.hs 然后在 ghci 中运行 ":l foo"。你可以通过运行 ":r" 来让 ghci 获取你的更改以进行刷新。
  • 那是 :l Orgdex.hs。我想我有不同版本的 Parsec
  • @ocharles 是的,我也这么认为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
相关资源
最近更新 更多