2013-11-10 2 views
1

Предположим, что существует какой-то парсер:Попробуйте разборе из следующего специального символа встречаемости, если анализатор провален

valid :: Parser String 
valid = string "valid" <* skipWhile (/= '\n') 

Это может быть использовано для получения "valid" строк из многострочного текста:

> parseOnly (many $ valid <* optional endOfLine) "valid\nvalid\nvalid" 
Right ["valid","valid","valid"] 

Если является линией, где valid Ошибка анализатора. Дальнейший текст не будет анализироваться вообще:

> parseOnly (many $ valid <* optional endOfLine) "valid\ninvalid\nvalid" 
Right ["valid"] 

Как получить Rigth["valid", "valid"] вместо этого? Я думал, что try может быть здесь полезен, но не уверен, как продолжить синтаксический анализ из следующей строки.

ответ

3

Использование парсек:

-- parser for the rest of the line 
rest = manyTill anyChar (eof <|> char '\n' *> return()) <* optional (char '\n') 

-- change this to accept lines, but Just the valid ones 
valid :: Parser (Maybe String) 
valid = (Just <$> string "valid" <|> const Nothing <$> anyChar) <* rest 

-- filter out Nothing 
valids = catMaybes <$> many valid 

-- Run 
*Foo> runParser valids() "input" "valid1\ninvvalid2\nvalid3" 
Right ["valid","valid"] 
*Foo> runParser valids() "input" "valid1\nvalid2\nvalid3" 
Right ["valid","valid","valid"] 

Здесь я должен сделать багги хак: const Nothing <$> anyChar так valid потребляющий всегда, по крайней мере что-то, иначе я не могу дать many. Однако, используя Maybe, вы можете переписать свой синтаксический анализатор по мере необходимости (например, сделать обязательной новую строку)

Очень похожий подход применим к attoparsec, извините за испорченность радости от его создания.

{-# LANGUAGE OverloadedStrings #-} 
import Data.Attoparsec.Text 
import Control.Applicative 
import Data.Maybe 
import Data.Text 

-- parser for the rest of the line 
rest = skipWhile (/= '\n') <* optional endOfLine 

-- change this to accept lines, but Just the valid ones 
valid :: Parser (Maybe Text) 
valid = (Just <$> string "valid" <|> const Nothing <$> anyChar) <* rest 

-- filter out Nothing 
valids = catMaybes <$> many valid 
*Main> parseOnly valids "valid1\nvalid2\nvalid3" 
Right ["valid","valid","valid"] 
*Main> parseOnly valids "valid1\ninvalid2\nvalid3" 
Right ["valid","valid"] 
+0

'<* необязательный (символ '\ п')' часть избыточна в 'rest'. Хорошее решение парсека, но вопрос касается attoparsec. –

+0

attoparsec очень похож. Некоторые примитивные парсеры называются по-разному, но общая структура идентична. – phadej

+0

Этот подход «Может быть» кажется разумным, спасибо. Кроме того, я удалил все связанные с текстом пакеты-распаковки, если вы не возражаете. –