Parsec的新手,一个初学者的问题。如何解析一些行可能为空的行文件,只包含空格后跟换行符?我只是想跳过它们,而不是在解析的输出中使用它们。
import Text.ParserCombinators.Parsec
-- alias for parseTest
run :: Show a => Parser a -> String -> IO ()
run = parseTest
-- parse lines
p :: Parser [[String]]
p = lineP `endBy` newline <* eof
where lineP = wordP `sepBy` (char ' ')
wordP = many $ noneOf "\n"
用空行解析示例:
*Main> run p "z x c\n1 2 3\n \na\n"
[["z x c"],["1 2 3"],[" "],["a"]]
我怀疑我这一切都错了。
答案 0 :(得分:4)
您可以定义一个自定义解析器,而不是使用newline
,它可以捕获行的结尾的您的概念,该解析器将解析至少一个newline
,然后可选的许多空行(即空格后跟另一个换行符)。如果空格后面没有其他换行符(或者输入结束,我猜),你需要try
运算符回溯:
代码:
-- parse lines
p :: Parser [[String]]
p = lineP `endBy` lineEnd <* eof
where lineP = wordP `sepBy` (char ' ')
wordP = many $ noneOf " \n"
lineEnd :: Parser ()
lineEnd = do
newline
many (try (many (oneOf " \t") >> newline))
return ()
输出:
*Main> run p "z x c\n1 2 3\n \na\n"
[["z","x","c"],["1","2","3"],["a"]]
答案 1 :(得分:4)
一种方法可能是将文件视为一系列空白或非空白的行。以下用表达式line <|> emptyLine
表达了这个想法。以下使用Maybe
数据类型来区分解析非空行的结果,使用catMaybes
过滤掉Nothing
s。
#!/usr/bin/env stack
{- stack
--resolver lts-7.0
--install-ghc
runghc
--package parsec
-}
import Prelude hiding (lines)
import Data.Maybe (catMaybes)
import Text.ParserCombinators.Parsec
-- parse lines
p :: Parser [[String]]
p = catMaybes <$> lines
where lines = (line <|> emptyLine) `endBy` newline <* eof
line = Just <$> word `sepBy1` spaces1
emptyLine = spaces1 >> pure Nothing
word = many1 $ noneOf ['\n', ' ']
spaces1 = skipMany1 (char ' ')
main = parseTest p "z x c\n1 2 3\n \na\n"
输出是:
[["z","x","c"],["1","2","3"],["a"]]
另一种方法可能是在开始之前使用Prelude
函数和Data.Char.isSpace
来收集非空行:
#!/usr/bin/env stack
{- stack
--resolver lts-7.0
--install-ghc
runghc
--package parsec
-}
import Data.Char
import Text.ParserCombinators.Parsec
p :: Parser [[String]]
p = line `endBy` newline <* eof where
line = word `sepBy1` spaces1
word = many1 $ noneOf ['\n', ' ']
spaces1 = skipMany1 (char ' ')
main = parseTest p (unlines nonBlankLines)
where input = "z x c\n1 2 3\n \na\n"
nonBlankLines = filter (not . all isSpace) $ lines input
输出是:
[["z","x","c"],["1","2","3"],["a"]]
这非常简单,并且还有一个额外的好处,即使用lines
在每行末尾不需要newline
(这有助于提高可移植性)。
注意,您的wordP
解析器存在一个小错误。另请注意,根据指定,这些解析器不处理前置或尾随空格(在非空行上)。我想象你的非最小代码更有弹性。