所以我有一个文件,其中第一行的格式为 ([String], [(Int, Int)], [(Int, Int)], Int)
,其余行的格式为 [((Int, Int), (Int, Int), String)]
。我设法获取输入并使用以下函数解析它:
someFunction :: String -> IO (String)
someFunction fileName = do
handle <- openFile fileName ReadMode
contents <- hGetLine handle
let firstLine = read contents :: ([String], [(Int, Int)], [(Int, Int)], Int)
restOfLines <- map read <$> lines <$> hGetContents handle :: IO [((Int, Int), (Int, Int), String)]
...
问题是,如果文件格式错误,我想打印自定义错误。因此,如果缺少某些东西或缺少某些东西,它应该只打印“一些错误”。否则,必须解析这些行,以便我可以对内容做一些其他的事情。如果有人能帮我解决这个问题,我将不胜感激。
答案 0 :(得分:0)
检测 Read
解析器是否失败的最简单方法是使用 readMaybe
。例如。在 GHCi 中:
> import Text.Read (readMaybe)
> :t readMaybe
readMaybe :: Read a => String -> Maybe a -- Defined in ‘Text.Read’
> readMaybe "1" :: Maybe Int
Just 1
> readMaybe ":(" :: Maybe Int
Nothing
您可以使用 readMaybe
对 case
的结果进行模式匹配,就像 Maybe
的任何其他用法一样:
case readMaybe input of
Just parsed -> … -- Use parsed value
Nothing -> … -- Report error
这只能报告一般性的失败;对于更复杂的解析和验证,您应该使用适当的解析库。 base
中包含的一个是 Text.ParserCombinators.ReadP
:
import Control.Applicative (some)
import Data.Char (isDigit)
import Text.ParserCombinators.ReadP (ReadP)
import qualified Text.ParserCombinators.ReadP as ReadP
-- Parse one or more digits.
number :: ReadP Int
number = read <$> some (ReadP.satisfy isDigit)
这些解析器可以使用 readP_to_S
对某些输入执行;默认情况下,它们会枚举所有可能的解析,您可以使用 eof
(需要完整输入)或 <++
(有偏见的选择)等函数对其进行约束。
> import Text.ParserCombinators.ReadP (readP_to_S)
> readP_to_S number "123"
[(1,"23"),(12,"3"),(123,"")]
> readP_to_S (number <* ReadP.eof) "123"
[(123,"")]
您可以对结果列表进行模式匹配以验证,例如,只有一个结果并提取您想要的内容或报告错误。另一个流行的解析库选择是 megaparsec
包,它可以额外提供带有源位置的漂亮的自定义错误消息。