3
作爲學習練習,我使用parsec在測試文件中查找值。我通常使用regexp來處理這個特定的情況,但是想看看parsec是否也有意義。不幸的是,我遇到了一些問題。使用parsec從文本文件中提取數據
數據文件由重複的部分組成,其外觀類似於以下內容。 'SHEF'是頁面之間的六個值之一和變化,我想用它來構造數據類型。
Part A SHEF Nov/14/2011 (10:52)
-------------------
Portfolio Valuation
-------------------
FOREIGN COMMON STOCK 6,087,152.65
FOREIGN COMMON STOCK - USA 7,803,858.84
RIGHTS 0.00
我構建量的數據類型中的每個資產類別:
type Sector = String
type Amount = Double
type FundCode = String
data SectorAmount = SectorAmount (Sector,Amount) deriving (Show, Eq)
data FundSectors = FundSectors {
fund :: FundCode
, sectorAmounts :: [SectorAmount]
} deriving (Show, Eq)
我的代碼,該代碼編譯成功,是如下所示。它解析文件並正確檢索每個資產類中的值,但我永遠無法在fundValue解析器中正確設置狀態。我已經用輸入字符串測試了fundValue解析器,並且它成功解析了它,但由於某種原因,行函數並不按照我認爲的方式工作。我希望它在文件中尋找以「Part A」開頭的行,找到代碼並將其存儲在狀態中,以便標記解析器成功解析行時供以後使用。
是否使用fail
導致該問題?
allocationParser :: String -> Either ParseError [FundSectors]
allocationParser input = do
runParser allocationFile "" "" input
allocationFile :: GenParser Char FundCode [FundSectors]
allocationFile = do
secAmt <- many line
return secAmt
line :: GenParser Char FundCode FundSectors
line = try (do fund <- try fundValue
eol
fail "")
<|> do result <- try tag
eol
f <- getState
return $ FundSectors {fund=f, sectorAmounts = [result]}
fundValue :: GenParser Char FundCode FundCode
fundValue = do manyTill anyChar . try $ lookAhead (string "Part A ")
string "Part A "
fCode <- try fundCode
setState fCode
v <- many (noneOf "\n\r")
eol
return fCode
fundCode :: GenParser Char FundCode String
fundCode = try (string "SHSF")
<|> try (string "SHIF")
<|> try (string "SHFF")
<|> try (string "SHEF")
<|> try (string "SHGE")
<|> try (string "SHSE")
<|> fail "Couldn't match fundCode"
tag :: GenParser Char FundCode SectorAmount
tag = do manyTill anyChar . try $ lookAhead tagName
name <- tagName
v <- many (noneOf "\n\r")
let value = read ([x | x <- v, x /= ',']) :: Double -- remove commas from currency
return $ SectorAmount (name,value)
eol :: GenParser Char FundCode String
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<|> fail "Couldn't find EOL"
在此先感謝。
謝謝克里斯,這很有道理。我認爲我掙扎的是,當我解析一條線時,我想要在設置狀態並返回任何內容時獲取一個fundValue,或者找到一個標記並返回一個數據類型,否則都不會。我想我可以使用'Maybe FundCode'並在找到fundValue時返回'Nothing',但這看起來效率很低,因爲'many line'會導致一個包含很多Nothing值的列表。我希望使用失敗能夠解決問題 - 有沒有其他方法可以與'many'一起使用,以便我可以設置狀態但不會返回值? – Neil
@Neil:這些'Nothing'值幾乎不會花費任何東西,並且幾乎在你用'(fmap catMaybes <$>多行)創建它們時'' – sclv
好點,謝謝@sclv,我會試一試。 – Neil