Haskell合并八进制校验与转十进制功能,单函数实现非法输入返0
实现方案
首先你现有代码有两处需要修正的问题:
- 你写的
isOcto校验逻辑有误:八进制合法字符范围是0~7,但你的判断条件digitToInt(x) > 0 && digitToInt(x) < 7只允许1~6的字符,漏掉了0和7两个合法值 - 没有判断输入字符是否为数字,直接调用
digitToInt处理非数字字符会抛出运行时异常
方案1:先校验后转换(逻辑清晰易读)
直接在校验通过后执行转换逻辑,非法输入直接返回0:
import Data.Char (digitToInt, isDigit) octoDec :: [Char] -> Int octoDec s = if isOcto s then convert s else 0 where -- 修正后的合法校验逻辑 isOcto [] = True isOcto (x:xs) = isDigit x && let d = digitToInt x in d >= 0 && d <= 7 && isOcto xs -- 原有转换逻辑 convert [] = 0 convert (x:xs) = digitToInt x * 8 ^ length xs + convert xs
方案2:单次遍历实现(效率更高)
不需要分两次遍历字符串(一次校验一次转换),用折叠操作在单次遍历中同时完成校验和转换,遇到非法字符直接返回0:
import Data.Char (digitToInt, isDigit) octoDec :: [Char] -> Int octoDec = fst . foldl process (0, True) where process (res, isValid) c | not isValid = (0, False) -- 已经判定非法,直接保持状态 | not (isDigit c) || d < 0 || d > 7 = (0, False) -- 遇到非法字符 | otherwise = (res * 8 + d, True) -- 正常计算十进制值 where d = digitToInt c
两种方案都满足需求:输入合法八进制字符串返回对应十进制值,输入包含非法字符时返回0。
内容的提问来源于stack exchange,提问作者Eduardo Machado
相关产品推荐
相关产品推荐

