我无法搞清楚这一点。
因此,如果一个字符串后跟一个或多个换行符,后面没有一个或多个空格 - 它就是行尾,我返回该行。如果一个字符串后跟一个或多个换行符,然后是一个或多个空格 - 它是一个行继续,我继续前进,直到我遇到没有空格的换行符。然后回来。
这完全锁定了我的大脑。请帮忙。
更新
如果上面的解释存在混淆,我举一个例子
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"]
答案 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
分支,并防止对正在解析的字符串的开头进行垃圾收集。