Parsec:线路延续问题

时间:2013-11-15 06:07:30

标签: haskell parsec

我无法搞清楚这一点。

因此,如果一个字符串后跟一个或多个换行符,后面没有一个或多个空格 - 它就是行尾,我返回该行。如果一个字符串后跟一个或多个换行符,然后是一个或多个空格 - 它是一个行继续,我继续前进,直到我遇到没有空格的换行符。然后回来。

这完全锁定了我的大脑。请帮忙。

更新

如果上面的解释存在混淆,我举一个例子

From: John Doe <j.doe@gmail.com>
To: dude@cooldomain.biz
Content-Type: multipart/alternative;
  boundary=047d7b2e4e3cdc627304eb094bfe

鉴于上述文本,我应该能够解析3行进行进一步处理,如此

["From: John Doe <j.doe@gmail.com>", "To: dude@cooldomain.biz", "Content-Type: multipart/alternative; boundary=047d7b2e4e3cdc627304eb094bfe"]

2 个答案:

答案 0 :(得分:1)

我建议将解析器分成多个传递,因此解析表达式的代码不会被空白处理混乱。例如:

  • lex :: String -> [Token]

    处理空格并将输入拆分为标记。

  • parse :: Parsec [Token] Expr

    将标记流转换为表达式树。

这是一种非常简单的方式来加入续行:

-- | For each line with whitespace in front of it,
-- remove it and append it to the preceding line.
joinContinuedLines :: [String] -> [String]
joinContinuedLines [] = []
joinContinuedLines (x0:xs0) = go x0 xs0
  where
    go joinedLine (x : xs)
      | startsWithSpace x = go (joinedLine ++ x) xs
      | otherwise         = joinedLine : go x xs
    go joinedLine [] = [joinedLine]

    startsWithSpace (x:_) = isSpace x
    startsWithSpace ""    = False

答案 1 :(得分:1)

可能是这样的伪代码(假设你想要保留所有的空格):

continuedLine = go "" where
    go s = do
        s'      <- many (noneOf "\n")
        empties <- many (char '\n')
        let soFar = s ++ s' ++ empties
        (char ' ' >> go (soFar ++ " ")) <|> return soFar

应用您最喜欢的转换,以消除深层嵌套的左侧关联++

编辑:嗯,我刚想到有一个我可能忽略的微妙之处。如果这不是一个延续,你是否希望将新线“取消”,可以这么说?如果是这样,您可以使用try执行以下操作:

continuedLine = go "" where
    continuationHerald = do
        empties <- many (char '\n')
        char ' '
        return (empties ++ " ")

    go s = do
        s'   <- many (noneOf "\n")
        cont <- try (Just <$> continuationHerald) <|> return Nothing
        case cont of
            Nothing -> return (s ++ s')
            Just empties -> go (s ++ s' ++ empties)

请注意,我们会花一些时间来避免在go内对try进行递归调用。这是一个效率问题:这样做会导致解析器拒绝放弃备用return Nothing分支,并防止对正在解析的字符串的开头进行垃圾收集。