2013-11-15 61 views
1

我无法弄清楚这一点。Parsec:线路延续故障

所以,如果一个字符串后面跟着一个或多个换行符,但后面没有一个或多个空格 - 它是行尾,我返回行。如果一个字符串后跟一个或多个换行字符,然后是一个或多个空格 - 这是一个续行,我继续前进,直到遇到没有空格的换行符。然后返回它。

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

UPDATE

在情况下,有一个关于我的解释混淆以上,我给鉴于上述文本我应该能够解析3线像这样进一步处理的示例

From: John Doe <[email protected]> 
To: [email protected] 
Content-Type: multipart/alternative; 
    boundary=047d7b2e4e3cdc627304eb094bfe 

["From: John Doe <[email protected]>", "To: [email protected]", "Content-Type: multipart/alternative; boundary=047d7b2e4e3cdc627304eb094bfe"] 

回答

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 

应用您最喜欢的转换来消除深度嵌套的左相关联的++

编辑:嗯,它只是我想到,我可能忽略了一个微妙的东西。如果这不是一个延续,你是否希望离开新行“unparsed”,可以这么说呢?如果是这样,你可以使用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) 

请注意,我们去一些长度,避免把递归调用gotry内。这是一个效率问题:这样做会导致解析器拒绝放弃替代return Nothing分支,并阻止垃圾收集被解析的字符串的开头。

+0

它怪异的作品!你是怎么做到的?那么,这是一个反问的问题......考虑到它的复杂性,我可能永远都不会想到它。我希望我错过了一些简单的事情。现在我需要浏览你的代码并理解它。通过查看输出结果,我意识到我需要从续行中剥离换行符和额外空格。你的第一个例子与我正在尝试做的类似,但是我会在换行符之后测试一个空格,然后在真正的情况下进行递归。虽然没有工作。那你为什么不喜欢你的第一个例子?它的工作原理也是如此。 –

+0

@ r.sendecky第一个代码段和第二个代码段的不同之处在于,第一个代码段消耗了非延续的换行符,但第二个代码段没有。 –

1

我建议把你的解析器分成多个遍,所以解析表达式的代码不是混乱的机智h空白处理。例如:

  • 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