Parsec: проблема продолжения строки

Мне трудно понять это.

Поэтому, если за строкой следует один или несколько символов новой строки без одного или нескольких пробелов после нее, это конец строки, и я возвращаю строку. Если за строкой следует один или несколько символов новой строки, а затем одно или много пробелов после этого - это продолжение строки, и я продолжаю идти до тех пор, пока не столкнутся с новыми символами без пробелов. Затем верните его.

Это просто заперло мой мозг. Пожалуйста помоги.

ОБНОВИТЬ

В случае возникновения путаницы в отношении моего объяснения выше, я приведу пример

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

Учитывая вышеприведенный текст, я должен разбирать 3 строки для дальнейшей обработки, например

["From: John Doe <j.[removed_email]>", "To: [removed_email]", "Content-Type: multipart/alternative; boundary=047d7b2e4e3cdc627304eb094bfe"]
</j.[removed_email]>
2 ответа

Возможно, что-то вроде этого псевдокода (если вы хотите сохранить все пробелы):

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

Примените свое любимое преобразование, чтобы устранить глубоко вложенные связанные с левом ++.

EDIT: Хм, мне просто пришло в голову, что у меня есть тонкость, которую я, возможно, забыл. В случае, если это не продолжение, надеетесь ли вы оставить строки "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)

Обратите внимание, что мы идем до некоторой длины, чтобы не допустить, чтобы рекурсивный вызов go внутрь try. Это проблема эффективности: это приведет к тому, что синтаксический анализатор откажется отказаться от альтернативного return Nothing, и предотвратите разбор мусора в начале строки.


Я предлагаю разбивать ваш парсер на несколько проходов, поэтому код для разбора выражений не загроможден с помощью обработки пробелов. Пример:

  • 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

licensed under cc by-sa 3.0 with attribution.