2011-02-12 159 views
122

有没有一种标准的方式来分割Haskell中的字符串?如何在Haskell中分割字符串?

lineswords在分隔空间或换行符方面效果很好,但肯定有一个标准的方式来分隔逗号?我无法在Hoogle上找到它?

具体而言,我正在寻找的东西在那里split "," "my,comma,separated,list"回报["my","comma","separated","list"]

感谢。

+14

我真的想在未来的`Data.List`甚至`Prelude`释放这样的功能。如果不可用于代码高尔夫球,那么这很常见和令人讨厌。 – fuz 2011-02-12 15:08:04

+0

这是分开的! – 2011-02-12 15:09:02

回答

109

这个包叫做split

cabal install split 

使用方法如下:

ghci> import Data.List.Split 
ghci> splitOn "," "my,comma,separated,list" 
["my","comma","separated","list"] 

它配备了很多其他功能上匹配的分隔符或有几个分隔符分割。

+8

很酷。我不知道这个软件包。这是最终拆分包,因为它可以对操作进行很多控制(修剪结果中的空白,结果中留下分隔符,删除连续的分隔符等等)。有很多分割列表的方式,不可能有单个分裂函数来回答每一个需求,你真的需要这种类型的包。 – gawi 2011-02-12 20:37:57

+1

否则,如果外部软件包可以接受,MissingH还提供了分离功能:http://hackage.haskell.org/packages/archive/MissingH/1.2.0.0/doc/html/Data-List-Utils.html#v:split该软件包还提供了许多其他“不错的功能”,我发现相当多的软件包依赖于它。 – 2012-12-13 10:44:24

+29

截至最新版本,拆分包现在已经是haskell平台的一部分。 – 2013-07-06 17:12:39

9

试试这个:

import Data.List (unfoldr) 

separateBy :: Eq a => a -> [a] -> [[a]] 
separateBy chr = unfoldr sep where 
    sep [] = Nothing 
    sep l = Just . fmap (drop 1) . break (== chr) $ l 

,只对单个字符,但应该很容易扩展。

17

在模块Text.Regex(Haskell的平台的一部分),有一个功能:

splitRegex :: Regex -> String -> [String] 

其将基于正则表达式的字符串。该API可在Hackage找到。

137

请记住,您可以查看Prelude函数的定义!

http://www.haskell.org/onlinereport/standard-prelude.html

看那里,words的定义是,

words :: String -> [String] 
words s = case dropWhile Char.isSpace s of 
         "" -> [] 
         s' -> w : words s'' 
          where (w, s'') = break Char.isSpace s' 

所以,改变它,需要一个谓词的函数:

wordsWhen  :: (Char -> Bool) -> String -> [String] 
wordsWhen p s = case dropWhile p s of 
         "" -> [] 
         s' -> w : wordsWhen p s'' 
          where (w, s'') = break p s' 

然后与任何断言叫它你要!

main = print $ wordsWhen (==',') "break,this,string,at,commas" 
5

我不知道如何添加注释到史蒂夫的答案,但我想推荐
    GHC libraries documentation
并在那里特别是
    Sublist functions in Data.List

作为参考,这要比阅读普通的Haskell报告好得多。一般来说,一个关于何时创建一个新的子列表以供应的规则的折叠也应该解决它。

5

我开始学习Haskell昨天,所以纠正我,如果我错了,但:

split :: Eq a => a -> [a] -> [[a]] 
split x y = func x y [[]] 
    where 
     func x [] z = reverse $ map (reverse) z 
     func x (y:ys) (z:zs) = if y==x then 
      func x ys ([]:(z:zs)) 
     else 
      func x ys ((y:z):zs) 

给出:

*Main> split ' ' "this is a test" 
["this","is","a","test"] 

或者你想

*Main> splitWithStr " and " "this and is and a and test" 
["this","is","a","test"] 

这将是:

splitWithStr :: Eq a => [a] -> [a] -> [[a]] 
splitWithStr x y = func x y [[]] 
    where 
     func x [] z = reverse $ map (reverse) z 
     func x (y:ys) (z:zs) = if (take (length x) (y:ys)) == x then 
      func x (drop (length x) (y:ys)) ([]:(z:zs)) 
     else 
      func x ys ((y:z):zs) 
11

使用Data.List.Split,它采用split

[[email protected]]$ ghci 
Prelude> import Data.List.Split 
Prelude Data.List.Split> let l = splitOn "," "1,2,3,4" 
Prelude Data.List.Split> :t l 
l :: [[Char]] 
Prelude Data.List.Split> l 
["1","2","3","4"] 
Prelude Data.List.Split> let { convert :: [String] -> [Integer]; convert = map read } 
Prelude Data.List.Split> let l2 = convert l 
Prelude Data.List.Split> :t l2 
l2 :: [Integer] 
Prelude Data.List.Split> l2 
[1,2,3,4] 
8
split :: Eq a => a -> [a] -> [[a]] 
split d [] = [] 
split d s = x : split d (drop 1 y) where (x,y) = span (/= d) s 

例如

split ';' "a;bb;ccc;;d" 
> ["a","bb","ccc","","d"] 

单个尾随分隔符将被丢弃:

split ';' "a;bb;ccc;;d;" 
> ["a","bb","ccc","","d"] 
2

除了给出答案的高效和预先内建的功能,我会加上我自己这只是我的Haskell的剧目的一部分功能我写学习语言上我自己的时间:

-- Correct but inefficient implementation 
wordsBy :: String -> Char -> [String] 
wordsBy s c = reverse (go s []) where 
    go s' ws = case (dropWhile (\c' -> c' == c) s') of 
     "" -> ws 
     rem -> go ((dropWhile (\c' -> c' /= c) rem)) ((takeWhile (\c' -> c' /= c) rem) : ws) 

-- Breaks up by predicate function to allow for more complex conditions (\c -> c == ',' || c == ';') 
wordsByF :: String -> (Char -> Bool) -> [String] 
wordsByF s f = reverse (go s []) where 
    go s' ws = case ((dropWhile (\c' -> f c')) s') of 
     "" -> ws 
     rem -> go ((dropWhile (\c' -> (f c') == False)) rem) (((takeWhile (\c' -> (f c') == False)) rem) : ws) 

的解决方案是至少尾递归,使他们不会产生一个堆栈溢出。

2

例如,在ghci的:

> import qualified Text.Regex as R 
> R.splitRegex (R.mkRegex "x") "2x3x777" 
> ["2","3","777"]