2016-11-23 30 views
1

在Haskell中,有没有可能包含分钟和秒(即,像这样34m30s)将字符串转换一些标准功能,它的分钟适当的Maybe Double?所以在这种情况下,我们会将34m30s转换为Just 34.5转换格式的字符串`<num>米<num> s`到`也许Double`占总分

+4

您是否有充分的理由将时间操作为“双倍”?为什么不把它放在一个很好的格式? ['time'](https://hackage.haskell.org/package/time-1.7)可以从你的格式解析'TimeOfDay':'parseTimeM False defaultTimeLocale“%Mm%Ss”“34m30s”'。 – Alec

+1

如果您需要将其转换为单个数值,请转换为整数秒,而不是“双倍”分钟。 – chepner

回答

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,并抓住任何其他列表的头部以获得唯一的答案。

+0

我想我应该指出,你可以添加“守卫”/条件的单子或理解refuset,例如,负值或秒值> = 60.单子,你会添加: –

+0

呃..击回车太早了。对于monad,你应该在适当的地方添加'guard $ mins> = 0'和'guard $ secs> = 0 && secs <= 59'。在列表理解中,你只写'mins> = 0'和'secs> = 0 && secs <= 59'从句,而不写“守护”。 –

2

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

import Data.Time 

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