Haskell程序运行报错:do块模式匹配失败,CSV多列表压缩功能实现求助
我来帮你一步步解决这个问题,先从最直接的报错说起,再梳理CSV处理的逻辑~
一、先解决模式匹配失败的崩溃问题
你遇到的t4.exe: user error (Pattern match failure in 'do' block at t4.hs:46:11-25)错误,根源很明确:运行程序时没有传入文件名参数,导致getArgs返回了空列表,而你的代码里(fileName : _ ) <- getArgs这个模式只能匹配「至少有一个元素的列表」,空列表匹配不上就直接触发了崩溃。
修改main函数,加上参数缺失的友好处理逻辑就行:
main :: IO () main = do args <- getArgs case args of (fileName : _) -> fileMZip fileName [] -> putStrLn "请指定输入CSV文件名,使用方式:./t4.exe 你的输入文件名.csv"
这样运行时如果没传参数,程序会提示正确用法,而不是直接崩溃。
二、修复CSV解析的逻辑漏洞
现在你的代码解析CSV的逻辑有问题:输入的每个字段是带引号和方括号的格式(比如"[1,2,3]"),但你直接用splitOn ','分割,会得到["\"[1", "2", "3]\""]这种不合法的数字字符串,后续map read肯定会失败。
我们需要先清理每个字段的格式,再解析成数字列表:
- 先把每行按空格分割成独立的列表字符串(处理输入中字段间的多空格)
- 对每个列表字符串,去掉首尾引号和方括号
- 再按逗号分割成单个数字字符串,最后转成
Int
可以写一个辅助函数来处理单个列表字符串:
parseListStr :: String -> [Int] parseListStr s = let -- 去掉首尾的引号 noQuotes = init (tail s) -- 去掉首尾的方括号 noBrackets = if head noQuotes == '[' then init (tail noQuotes) else noQuotes -- 分割逗号并过滤空字符串(避免连续逗号的情况) numStrs = filter (not . null) $ splitOn ',' noBrackets in map read numStrs
然后修改fileMZip'里的解析部分:
fileMZip' fileName = do s <- readFile fileName let ls = lines s -- 每行按空格分割成列表字符串,过滤空元素(处理多空格) lineFields = map (filter (not . null) . splitOn ' ') ls -- 解析每个字段为Int列表 iss = map (map parseListStr) lineFields mss = multiZipL iss -- 把结果列表转成要求的带引号和方括号的格式 listToStr xs = "\"[" ++ intercalate "," (map show xs) ++ "]\"" oss = map (intercalate " " . map listToStr) mss css = intercalate "\n" oss writeFile "ziplists.csv" css
三、优化多列表压缩的逻辑(可选)
你的multiZipL和nltail逻辑是对的,但可以整合得更简洁一点,去掉单独的nltail函数:
multiZipL :: [[a]] -> [[a]] multiZipL [] = [] multiZipL xss = case filter (not . null) xss of [] -> [] ys -> map head ys : multiZipL (map tail ys)
这个版本和你原来的逻辑完全一致,但可读性更高。
四、测试验证
现在用你给出的输入测试:
输入行:"[1,2,3]" "[5,24,3]" "[1,3,4,5]" "[0,8,6]"
解析后得到:[[1,2,3],[5,24,3],[1,3,4,5],[0,8,6]]
经过multiZipL处理后得到:[[1,5,1,0],[2,24,3,8],[3,3,4,6],[5]]
最终输出到ziplists.csv的内容就是:
"[1,5,1,0]" "[2,24,3,8]" "[3,3,4,6]" "[5]"
完全符合你的需求~
备注:内容来源于stack exchange,提问作者Alberto Berni

