2013-11-15 90 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