На этот раз я пытаюсь разобрать текстовый файл на [[String]]
с использованием Parsec. Результат - это список, состоящий из списков, представляющих строки файла. Каждая строка представляет собой список, содержащий слова, которые могут быть разделены любым количеством пробелов (необязательно) запятыми и пробелами после запятых.Исчезающий конец строки с Parsec
Вот мой код, и он даже работает.
import Text.ParserCombinators.Parsec hiding (spaces)
import Control.Applicative ((<$>))
import System.IO
import System.Environment
myParser :: Parser [[String]]
myParser =
do x <- sepBy parseColl eol
eof
return x
eol :: Parser String
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"
spaces :: Parser()
spaces = skipMany (char ' ') >> return()
parseColl :: Parser [String]
parseColl = many parseItem
parseItem :: Parser String
parseItem =
do optional spaces
x <- many1 (noneOf " ,\n\r")
optional spaces
optional (char ',')
return x
parseText :: String -> String
parseText str =
case parse myParser "" str of
Left e -> "parser error: " ++ show e
Right x -> show x
main :: IO()
main =
do fileName <- head <$> getArgs
handle <- openFile fileName ReadMode
contents <- hGetContents handle
putStr $ parseText contents
hClose handle
Тестовый файл:
это мой тестовый файл
это, линия, есть, отделенные, по, запятые
и это еще одна, линия
Результат:
[["this","is","my","test","file"],
["this","line","is","separated","by","commas"],
["and","this","is","another","line"],
[]] -- well, this is a bit unexpected, but I can filter things
Теперь, чтобы сделать мою жизнь более трудной, я хочу иметь возможность «сбежать» eol
, если перед ней есть запятая ,
, даже если запятая содержит пробелы. Так что это должно рассматриваться одна строка:
это, пространства может быть здесь
моя линия
Что лучшая стратегия (наиболее идиоматических и элегантный) реализовать этот синтаксис (без теряя способность игнорировать запятые внутри строки).
Parsec отлично, но для чего-то такого простого, почему бы не использовать 'lines' и' words', а затем запустить вывод через то, что удаляет запятые и запятые, а затем фильтрует пустые строки? Иногда необходим полный анализ, но для чего-то такого простого, это выглядит излишним для меня. – jamshidh
@jamshidh, вы правы, но это не настоящая программа. Это упрощенный пример. В моей реальной программе я не могу уйти с 'lines' и' words' ... – Mark
Не определено ли parsec eof? https://hackage.haskell.org/package/parsec-3.0.0/docs/Text-ParserCombinators-Parsec-Combinator.html#v:eof – Arnon