将形式为`<num> m <num> s`的字符串转换为`Maybe Double`代表总分钟数

时间:2016-11-23 02:07:34

标签: haskell time

在Haskell中,是否有一些标准函数将可能包含分钟和秒的字符串(即类似34m30s之类)转换为适当的Maybe Double分钟?因此,在这种情况下,我们会将34m30s转换为Just 34.5

2 个答案:

答案 0 :(得分:2)

您可以使用Data.Time.Format.parseTimeMString转换为TimeOfDay,然后将其转换为DiffTimeDouble

import Data.Time

parseMS :: String -> Maybe Double
parseMS = fmap (realToFrac . (/ 60) . timeOfDayToTime) . parseTimeM False defaultTimeLocale "%Mm%Ss"

答案 1 :(得分:2)

基于parseTimeM的答案似乎只有在分钟和秒数恰好是两位数时才有效,因此parseMS "1m30s"parseMS "12m0s"都会产生Nothing

你真的需要一个简单的解析器。这是在List monad中使用reads调用的一个。请注意,它将需要带有“m”和“s”后缀的分钟和秒钟部分,因此“10m”和“10m30”和“15s”都将产生Nothing。此外,它会接受负数和前导空格,因此" 10m -30s"会返回Just 9.5

import Data.Maybe (listToMaybe)

readMS :: String -> Maybe Double
readMS str = listToMaybe $ do
  (mins, 'm':rest1) <- reads str
  (secs, "s")       <- reads rest1
  return (fromIntegral (mins :: Int) + fromIntegral (secs :: Int) / 60)

有些人在使用等效列表理解编写时更容易理解,如下所示:

readMS1 :: String -> Maybe Double
readMS1 str = listToMaybe
  [ fromIntegral (mins :: Int) + fromIntegral (secs :: Int) / 60
  | (mins, 'm':rest1) <- reads str
  , (secs, "s")       <- reads rest1
  ]

如果您之前没有看过这种风格,请注意:我们正在使用List monad,每个reads调用都会返回一个可能的解析列表(value,rest_of_string)对。 do-block的第一行获得整数mins的每个可能的解析,后跟字母“m”加上字符串的rest1。第二行将每个可能的rest1解析为整数secs,后跟字母“s”,而不是其他任何内容。

如果匹配失败(例如,字符串末尾没有“s”),则monad / comprehension返回空列表。否则,它返回所有可能解析的计算双打列表(在这种情况下,最多只有一个)。 listToMaybe函数将空列表转换为Nothing并抓取任何其他列表的头部以获得唯一答案。