parsec中意外的输入结束

时间:2011-06-04 07:15:36

标签: haskell parsec

我想解析这样的文件:

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行时。所以几次尝试后我都没能解决这个问题。

4 个答案:

答案 0 :(得分:5)

我最好的猜测是whiteSpace中的line消耗了换行符。因此,整个文件由一个line解析器解析,而eol解析器永远不会有机会获得"\n"。尝试将whiteSpace替换为many (char ' '),看看是否有帮助。

答案 1 :(得分:4)

这是一个使用原始字符解析器而不是令牌解析器的工作实现。注意 - 不使用空格作为分隔符更强大,但如果它存在则删除它。如果你使用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

答案 2 :(得分:1)

我打赌你错过了最后一行末尾的换行符。 对于解析完整的行,它应该是“861:1 \ n”但它可能是“861:1EOF”。 因此,我认为您的解析器正确识别您的输入是不正确的。

答案 3 :(得分:0)

实际上,我发现你可以使用whiteSpace(例如,轻松忽略多行块注释),同时仍然是面向行的。只需在换行时包含此解析器。

col (== 1) "only matches beginning of line"

col pred errStr = do
  c <- sourceColumn <$> getPosition
  if pred c then return ()
            else unexpected errStr