Haskell中split函数单行实现诉求:期望纳入Prelude并由base函数组合
用Base库实现可纳入Prelude的Split函数
嘿,这个问题我太有共鸣了——split绝对是文本处理里的刚需,但base库偏偏没把它直接放进Prelude,每次要自己实现确实有点挠头。不过用base里的现有函数完全能写出简洁好用的版本,我给你分享几个实用的思路:
1. 单个字符分隔的基础递归版本
这是最直观也最简洁的实现,只用了Prelude自带的break函数和模式匹配,处理连续分隔符时也能保留空字符串(比如split ',' "a,,b"会得到["a","","b"]):
split :: Eq a => a -> [a] -> [[a]] split delim s = case break (== delim) s of (chunk, _:rest) -> chunk : split delim rest -- 找到分隔符,取出前半段继续递归 (chunk, []) -> [chunk] -- 没有分隔符了,返回最后一段
2. 用unfoldr实现更紧凑的版本
如果你喜欢更函数式的风格,可以用Data.List里的unfoldr(Data.List默认被Prelude包含,不需要额外导入),代码更紧凑:
import Data.List (unfoldr) split :: Eq a => a -> [a] -> [[a]] split delim = unfoldr $ \remaining -> if null remaining then Nothing else let (chunk, rest) = break (== delim) remaining in Just (chunk, drop 1 rest)
3. 支持字符串分隔符的版本
如果需要按字符串而非单个字符分割(比如按"||"分割文本),可以用base的isPrefixOf实现:
import Data.List (isPrefixOf) splitOn :: Eq a => [a] -> [a] -> [[a]] splitOn delim s | null delim = error "splitOn: 分隔符不能为空字符串" | null s = [] | delim `isPrefixOf` s = splitOn delim (drop (length delim) s) | otherwise = let (c:cs) = s in case splitOn delim cs of [] -> [[c]] (first:rest) -> (c:first) : rest
这个版本会正确处理比如splitOn "||" "a||b|||c"得到["a","b","","c"]的场景。
加入自定义Prelude
把这些函数放到你自己的自定义Prelude模块里(比如MyPrelude.hs),然后在项目里默认导入它,就能像用原生Prelude函数一样用split了!
内容的提问来源于stack exchange,提问作者luochen1990
相关产品推荐
相关产品推荐

