我正在编写我的第一个 Haskell 程序。该程序解析普通的 CSV 文件,但我遇到了许多问题,这些问题无疑源于我对语法的缺乏经验。
目前,代码成功解析了一条记录,但在最后一条记录上,解析器占用了换行符,因此不处理后续行的记录。
我提出的解决方案是在我的 fieldData 规范中添加一个检查以检查“takeTill 选项卡或换行符”,但我不知道该怎么做。
当前代码:
fieldData = takeTill (== '\t')
尝试:
fieldData = takeTill (== '\t' || '\n') -- wrong, something about infix precedence
fieldData = takeTill (== ('\t' || '\n')) -- wrong, type error
fieldData = takeTill ((== '\t') || (== '\n')) -- wrong, type error
fieldData x = takeTill ((x == '\t') || (x == '\n')) -- wrong, type error
fieldData x = takeTill x ((x == '\t') || (x == '\n')) -- wrong, not enough arguments
我觉得我对如何在 Haskell 中构造布尔条件有一些基本的误解,希望得到帮助。例如,在 ghci 中我可以做到let fun x = (x == 'a' || x == 'b')
,它会很好地匹配不同的字符,所以在将它与函数一起使用时,我显然遗漏了一些东西。
或者,这甚至是正确的方法吗?如果这不是解决问题的正确方法,我将不胜感激指向“正确”方法的指针。
完整代码如下:
{- Parsing a tab-separated file using Attoparsec.
A record contains:
number\tname\tgenre\tabilities\tweapon\n
-}
import System.FilePath.Posix
import Data.Attoparsec.Char8
import Control.Applicative
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C
data AbilitiesList = AbilitiesList String deriving Show
data PlayerCharacter = PlayerCharacter {
id :: Integer,
name :: String,
genre :: String,
abilities :: AbilitiesList,
weapon :: String
} deriving Show
type Players = [PlayerCharacter]
fieldData = takeTill (== '\t')
tab = char '\t'
parseCharacter :: Parser PlayerCharacter
parseCharacter = do
id <- decimal
tab
name <- fieldData
tab
genre <- fieldData
tab
abilities <- fieldData
tab
weapon <- fieldData
return $ PlayerCharacter id (C.unpack name) (C.unpack genre) (AbilitiesList (C.unpack abilities)) (C.unpack weapon)
abilitiesFile :: FilePath
abilitiesFile = joinPath ["data", "ff_abilities.txt"]
playerParser :: Parser Players
playerParser = many $ parseCharacter <* endOfLine
main :: IO ()
main = B.readFile abilitiesFile >>= print . parseOnly playerParser