5

次のようなファイルを解析したい:

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"

私のdata.testファイルに10行しかないのに、なぜ11行目と言ったのかわかりません。そのため、何度か試行した後、この問題を修正できませんでした。

4

4 に答える 4

5

私の最善の推測は、改行を消費していることですwhiteSpacelineしたがって、ファイル全体が単一lineのパーサーによって解析されており、eolパーサーが"\n". に置き換えwhiteSpaceてみてmany (char ' ')、それが役立つかどうかを確認してください。

于 2011-06-04T07:29:08.843 に答える
4

これは、トークン パーサーではなくプリミティブ char パーサーを使用した実用的な実装です。注 - 空白をセパレータとして使用せず、存在する場合は削除する方が堅牢です。1 行の do 記法を使用した部分は(<*)、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
于 2011-06-04T11:20:56.163 に答える
1

最後の行の最後に改行がありません。完全な行を解析するには、「861:1\n」である必要がありますが、おそらく「861:1EOF」です。したがって、パーサーは入力が正しくないと正しく識別していると思います。

于 2011-06-04T09:00:56.630 に答える
0

実際、行指向でありながら、(たとえば、複数行のブロック コメントを簡単に無視するために) whiteSpace を使用できることがわかりました。改行が必要な場合は、このパーサーを含めるだけです。

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

col pred errStr = do
  c <- sourceColumn <$> getPosition
  if pred c then return ()
            else unexpected errStr
于 2013-10-04T11:53:44.897 に答える