Using parsec:
-- 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"]
Here i have to make a buggy hack: const Nothing <$> anyChar
so valid
consumes always at least something, otherwise I can't give it to many
. However using Maybe
you can rewrite your parser as you need (eg making newline mandatory)
Very similar approach is applicable with attoparsec, sorry for spoiling the joy of making it yourself.
{-# 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"]