问题描述
|
我想解析这样的文件:
66:3 3:4
329:2
101:3
495:4
55:5
268:5
267:2
242:4
262:1
861:1
我的代码如下:
getTestData :: String -> IO [[(Int,Int)]]
getTestData name = do
--res <- parseFromFile testData (name ++ \".test\")
fc <- readFile (name ++ \".test\")
let res = parse testData \"test data\" fc
case res of
Left e -> error $ show e-- \"test data parse eror.\"
Right ts -> return ts
eol = char \'\\n\'
testData = endBy line eol
--testData = many line
testTuple = do
i <- natural
colon
r <- natural
return (fromIntegral i:: Int,fromIntegral r:: Int)
line = sepBy testTuple whiteSpace
但是在运行时,它将引发异常:
ts <- getTestData \"data\"
*** Exception: \"test data\" (line 11,column 1):
unexpected end of input
expecting natural or \"\\n\"
我不明白,为什么说11行,而我的data.test文件只有10行。因此,经过多次尝试,我未能解决此问题。
解决方法
我最好的猜测是,ѭ3中的ѭ2正在消耗换行符。因此,您的整个文件都由单个
line
解析器进行解析,而ѭ5never解析器将永远不会有机会获得\"\\n\"
。尝试将whiteSpace
替换为many (char \' \')
,看看是否有帮助。
, 这是使用原始字符解析器而不是令牌解析器的有效实现。注意-不使用空格作为分隔符,而是将其删除(如果存在则更为健壮)。如果您使用Applicative中的(<*)
,则我使用过一行注解符号的位会更加整洁。
{-# OPTIONS -Wall #-}
module ParsecWhite where
import Text.ParserCombinators.Parsec
import Data.Char
main = getTestData \"sample\"
getTestData :: String -> IO [[(Int,Int)]]
getTestData name = do
--res <- parseFromFile testData (name ++ \".test\")
fc <- readFile (name ++ \".test\")
let res = parse testData \"test data\" fc
case res of
Left e -> error $ show e -- \"test data parse eror.\"
Right ts -> return ts
testData :: Parser [[(Int,Int)]]
testData = input
input :: Parser [[(Int,Int)]]
input = many (do { a <- line; newline; return a })
<?> \"input\"
line :: Parser [(Int,Int)]
line = many (do { a <- testTuple; softWhite; return a}) <?> \"line\"
testTuple :: Parser (Int,Int)
testTuple = do
i <- natural
colon
r <- natural
return (i,r)
<?> \"testTuple\"
softWhite :: Parser ()
softWhite = many (oneOf \" \\t\") >> return ()
colon :: Parser ()
colon = char \':\' >> return ()
natural :: Parser Int
natural = fmap (post 0) $ many1 digit
where
post ac [] = (ac * 10)
post ac [x] = (ac * 10) + digitToInt x
post ac (x:xs) = post ((ac * 10) + digitToInt x) xs
, 我敢打赌,您在最后一行的末尾缺少换行符。
为了解析完整的行,它应该是\“ 861:1 \\ n \”,但可能是\“ 861:1EOF \”。
因此,我认为您的解析器正确地将您的输入标识为不正确。
, 实际上,我发现您可以使用whiteSpace(例如,轻松地忽略多行块注释),同时仍然是面向行的。只需在需要换行符时包括此解析器。
col (== 1) \"only matches beginning of line\"
col pred errStr = do
c <- sourceColumn <$> getPosition
if pred c then return ()
else unexpected errStr