检查字符串中的价格值是否格式正确

时间:2011-05-21 16:44:49

标签: parsing haskell

我使用n< - getLine来获取用户价格。我如何检查值是否正确? (价格可以有'。'和数字,但必须大于0)?


不起作用:

isFloat = do
    n <- getLine
    let val = case reads n of
                ((v,_):_) -> True
                _ -> False

2 个答案:

答案 0 :(得分:4)

如果输入始终有效或例外情况正常

如果您让用户以“123.456”的形式输入十进制数字,则只需使用read将其转换为Float或Double:

n <- getLine
let val = read n

或者在一行中(已导入Control.Monad):

n <- liftM read getLine

捕获错误输入

如果用户输入无效条目,则上述代码失败并出现异常。如果这是一个问题,那么使用read和listToMaybe(来自Data.Maybe):

n <- liftM (fmap fst . listToMaybe . reads) getLine

如果该代码看起来很复杂,那就不要惹恼 - 下面的操作是相同的,但是使用明确的case语句进行所有工作:

n <- getLine
let val = case reads n of
            ((v,_):_) -> Just v
            _ -> Nothing

注意我们模式匹配以获取列表头部中元组的第一个元素,列表的头部为(v,_),第一个元素为v。下划线(_)仅表示“忽略此点中的值”。

如果浮点不可接受

众所周知,浮动值是近似值,不适合现实世界的财务计算(但也许是家庭作业,取决于您的教授)。在这种情况下,您需要将值读入Rational(来自Data.Ratio)。

n <- liftM maybeRational getLine
...
  where
  maybeRational :: String -> Maybe Rational
  maybeRational str =
      let (a,b) = break (=='.') str
      in liftM2 (%) (readMaybe a) (readMaybe $ drop 1 b)
  readMaybe = fmap fst . listToMaybe . reads

答案 1 :(得分:1)

除了TomMD提供的解析建议之外,请考虑使用适当的monad进行错误报告。它允许您方便地链接可能失败的计算,避免在每个步骤上进行显式错误检查。

{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Error

parsePrice :: MonadError String m => String -> m Double
parsePrice s = do
    x <- case reads s of
        [(x, "")] -> return x
        _         -> throwError "Not a valid real number."
    when (x <= 0) $ throwError "Price must be positive."
    return x

main = do
    n <- getLine
    case parsePrice n of
        Left err -> putStrLn err
        Right x  -> putStrLn $ "Price is " ++ show x