Haskell 使用parsec解析文件

Haskell 使用parsec解析文件,haskell,parsec,Haskell,Parsec,我试图解析文件[1],但下面的代码无法正常工作 import Control.Applicative hiding ( many , ( <|> ) ) import Text.Parsec import Text.Parsec.String (Parser) import qualified Text.Parsec.Token as T import Text.Parsec.Language (emptyDef) --Scheme Code;ISIN Div Payout/

我试图解析文件[1],但下面的代码无法正常工作

import Control.Applicative hiding ( many , ( <|> )  )
import Text.Parsec
import Text.Parsec.String (Parser) 
import qualified Text.Parsec.Token as T
import Text.Parsec.Language (emptyDef)

--Scheme Code;ISIN Div Payout/ ISIN Growth;ISIN Div Reinvestment;Scheme Name;Net Asset Value;Repurchase Price;Sale Price;Date
--120523;INF846K01ET8;INF846K01EU6;Axis Triple Advantage Fund - Direct Plan - Dividend Option;13.3660;13.2323;13.3660;19-Jun-2015

data MFund = MFund Integer  String String String Double Double Double String deriving (Show) --String String String  deriving (Show)

lexer :: T.TokenParser st
lexer  = T.makeTokenParser emptyDef

natural :: Parser Integer
natural = T.natural lexer

float :: Parser Double
float = T.float lexer

eol :: Parser String
eol =  try (string "\r\n")
   <|> try (string "\n")
   <|> try (string "\r")

parseFund :: Parsec String () MFund
parseFund = MFund <$> natural 
              <*> (char ';' *> (many1 alphaNum <|> string "-")) 
              <*> (char ';' *> (many1 alphaNum <|> string "-")) 
              <*> (char ';' *> manyTill anyChar (char ';'))
              <*> float
              <*> (char ';' *> float)
              <*> (char ';' *> float)
              <*> (char ';' *> many1 (alphaNum <|> char '-'))



parseBlockFund :: Parsec String () [MFund]
parseBlockFund = manyTill anyChar eol *> space *> eol *> endBy parseFund eol

parseMutual :: Parsec String () [MFund]
parseMutual = concat <$> (manyTill anyChar eol *> space *> eol *>
          sepBy parseBlockFund (space *> eol))

{- each scheme is seperated by space and end of line-}
parseSchemeBlock :: Parsec String () [MFund]
parseSchemeBlock = concat <$> (sepBy parseMutual (space *> eol))

parseFile :: Parsec String () [MFund]
parseFile = 
   string "Scheme Code;ISIN Div Payout/ ISIN Growth;ISIN Div Reinvestment;Scheme Name;Net Asset Value;Repurchase Price;Sale Price;Date" *>
   eol *> space *> eol *> parseSchemeBlock <* eof


main :: IO ()
main = do 
 input <- readFile "data.txt"
 print input
 case parse  parseFile  "" input  of
    Left err -> print err
    Right val -> print val
导入控制。应用程序隐藏(许多,()) 导入文本.Parsec 导入Text.Parsec.String(解析器) 将限定的Text.Parsec.Token作为T导入 导入Text.Parsec.Language(emptyDef) --方案代码;ISIN部门支出/ISIN增长;ISIN部门再投资;方案名称;资产净值;回购价格;销售价格;日期 --120523;INF846K01ET8;INF846K01EU6;安讯士三重优势基金-直接计划-分红期权;13.3660;13.2323;13.3660;2015年6月19日 数据MFund=MFund整数字符串派生(显示)--字符串派生(显示) lexer::T.TokenParser st lexer=T.makeTokenParser emptyDef 自然::解析器整数 自然的,自然的 浮点::分析器双精度 float=T.float lexer eol::解析器字符串 eol=try(字符串“\r\n”) try(字符串“\n”) try(字符串“\r”) parseFund::Parsec String()MFund parseFund=MFund natural (字符“;”*>(多个字母数字字符串“-”) (字符“;”*>(多个字母数字字符串“-”) (char';'*>manyTill anyChar(char';')) 浮动 (字符“;”*>浮点) (字符“;”*>浮点) (字符“;”*>many1(alphaNum字符“-”) parseBlockFund::Parsec字符串()[MFund] parseBlockFund=manyTill anyChar eol*>space*>eol*>endBy parseFund eol parseMutual::Parsec字符串()[MFund] parseMutual=concat(manyTill anyChar eol*>space*>eol*> Sebby parseBlockFund(空间*>eol)) {-每个方案由空格和行尾分隔-} parseSchemeBlock::Parsec字符串()[MFund] parseSchemeBlock=concat(sebby parseMutual(空格*>eol)) parseFile::Parsec字符串()[MFund] 解析文件= 字符串“方案代码;ISIN Div支出/ISIN增长;ISIN Div再投资;方案名称;资产净值;回购价格;销售价格;日期”*> eol*>space*>eol*>parseSchemeBlock打印值 我开始从parseFile函数解析文件,该函数使用第一行、行尾、空格和行尾。现在,我解析每个由空格和行尾分隔的scheme块。在每个scheme块中,我们有许多共同块,它们也由空格和行尾分隔,因此我首先使用字符串,直到行尾,然后是空格和行尾,然后调用parseBlockFund

我怀疑的问题是,当我调用parseMutual函数时,当它到达scheme块的末尾时,它会占用parseSchemeBlock函数应该占用的空间和行尾。我尝试了try函数,但它不起作用,所以我不确定我的想法是否正确。谁能告诉我这个密码有什么问题吗

当我删除eof时,一件有趣的事情是,这段代码能够解析至少一个scheme块[2]

[1]


[2]

很难跟踪应该在何处使用空白,因为代码在许多地方都分散在
空间
eol
中。使用这样一种简单的基于行的格式,您确实希望一次处理整行。我会尝试编写一个
line::Parser a->Parser a
combinator,它解析
a
,然后热切地咀嚼空格和换行符。(但要小心,
a
本身不会使用换行符。)