You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求Haskell函数expand :: String -> [(Char,Int)]:字符数字串转字符整数对列表

嘿,这个需求我之前也碰到过!要实现expand :: String -> [(Char,Int)]来把"a5b3c2"这类字符串转成字符数字对列表,其实可以从字符串的结构入手——它本质就是单个非数字字符 + 一串数字重复组成的序列对吧?

基础递归实现(快速上手)

最直接的方式就是用递归遍历字符串:每次取第一个字符,然后提取后面跟着的所有连续数字,把数字转成Int后组成元组,再递归处理剩下的部分。代码如下:

import Data.Char (isDigit)

expand :: String -> [(Char, Int)]
expand [] = []
expand (char:remaining) = (char, read numChars) : expand rest
  where
    -- 把剩余字符串拆成数字部分和后续字符部分
    (numChars, rest) = span isDigit remaining

来测试你的示例:

expand "a5b4c2" -- 返回 [('a',5),('b',4),('c',2)]
expand "d9d3"   -- 返回 [('d',9),('d',3)]

不过这个版本有个小问题:如果输入不合法(比如结尾是单独字符"a",或者数字部分是空),read会直接抛出错误。如果需要更健壮的错误处理,可以改成返回Maybe类型:

健壮版(带错误处理)

import Data.Char (isDigit)
import Text.Read (readMaybe)

expand :: String -> Maybe [(Char, Int)]
expand [] = Just []
expand (char:remaining) = case span isDigit remaining of
  -- 字符后面没有数字,输入无效
  ([], _) -> Nothing
  (numChars, rest) -> do
    num <- readMaybe numChars
    restPairs <- expand rest
    return $ (char, num) : restPairs

现在如果输入"a",会返回Nothing而不是崩溃,更适合生产环境。

进阶:用解析器组合子(Parsec)

如果你的场景需要更复杂的输入验证,比如严格区分字母和数字,或者处理更复杂的格式,用Parsec这类解析器组合子会更优雅:

import Text.Parsec
import Text.Parsec.String (Parser)

-- 定义单个字符数字对的解析器
pairParser :: Parser (Char, Int)
pairParser = do
  -- 匹配一个非数字字符(如果只需要字母可以换成letter)
  char <- noneOf ['0'..'9']
  -- 匹配一串数字并转成Int
  num <- read <$> many1 digit
  return (char, num)

-- 扩展整个字符串
expand :: String -> Either ParseError [(Char, Int)]
expand = parse (many pairParser) "expand input"

这个版本会返回Either ParseError [(Char,Int)],如果输入不合法,会告诉你具体哪里出错了,比如输入"a5x"会提示unexpected end of input,因为x后面没有数字。

内容的提问来源于stack exchange,提问作者Hamza Halabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:04:59