2010-12-21 138 views
19

我试图通过1功能上用分隔符分隔字符串的最佳方法是什么?

写在Haskell程序,将采取由逗号定界整数一串数字,将其转换为整数的列表,并增加每个号码例如 "1,2,-5,-23,15" -> [2,3,-4,-22,16]

下面是生成的程序

import Data.List 

main :: IO() 
main = do 
    n <- return 1 
    putStrLn . show . map (+1) . map toInt . splitByDelimiter delimiter 
    $ getList n 

getList :: Int -> String 
getList n = foldr (++) [] . intersperse [delimiter] $ replicate n inputStr 

delimiter = ',' 

inputStr = "1,2,-5,-23,15" 

splitByDelimiter :: Char -> String -> [String] 
splitByDelimiter _ "" = [] 
splitByDelimiter delimiter list = 
    map (takeWhile (/= delimiter) . tail) 
    (filter (isPrefixOf [delimiter]) 
     (tails 
      (delimiter : list))) 

toInt :: String -> Int 
toInt = read 

对我来说,最困难的部分是一个字符串并将返回字符串

列表的功能 splitByDelimiter编程

"1,2,-5,-23,15" -> ["1","2","-5","-23","15"]

认为它工作,我不满意它的写法。有很多括号,所以它看起来像Lisp。同样的算法是有点人为:

  1. 前面加上分隔字符串的开头",1,2,-5,-23,15"

  2. 生成所有的尾巴[",1,2,-5,-23,15", "1,2,-5,-23,15", ",2,-5,-23,15", .... ]

  3. 过滤器的列表,只留下与分隔符开头的字符串[",1,2,-5,-23,15", ",2,-5,-23,15", .... ]

  4. 放下第一个分隔符并采用符号,直到达到下一个分隔符["1", "2", .... ]

所以问题是:

我怎样才能改善功能splitByDelimiter

我可以删除前缀和删除分隔符并直接拆分字符串吗?

如何重写函数以减少括号?

可能我错过了一些东西,并且已经有了这个功能的标准功能?

+0

`foldr相似(++)[] `也被称为`concat`,`putStrLn。 show`也被称为`print`。另外,`n < - return 1`有点奇怪;你可以做'让n = 1'并避免包装和解开monad。 – pat 2013-02-27 02:36:30

+0

可能的重复[如何在Haskell中拆分字符串?](http://stackoverflow.com/questions/4978578/how-to-split-a-string-in-haskell) – 2014-07-02 15:39:42

回答

29

是不是Data.List.Split.splitOn这样做?

+6

鉴于此包不是基本安装(Haskell平台),我认为它容易被忽视。 – 2010-12-21 21:27:48

+0

谢谢。它完全符合我的需求。 – sign 2010-12-21 21:33:12

11

这是一个黑客,但它,它的作品。

yourFunc str = map (+1) $ read ("[" ++ str ++ "]") 

下面是使用unfoldr非破解版:

import Data.List 
import Control.Arrow(second) 

-- break' is like break but removes the 
-- delimiter from the rest string 
break' d = second (drop 1) . break d 

split :: String -> Maybe (String,String) 
split [] = Nothing 
split xs = Just . break' (==',') $ xs 

yourFunc :: String -> [Int] 
yourFunc = map ((+1) . read) . unfoldr split 
+0

谢谢。这是一个很好的观点。我喜欢在这里使用不同的展示方式。 – sign 2010-12-21 22:19:19

4

这是应用HaskellElephant的回答原来的问题,有轻微的变化

 
splitByDelimiter :: Char -> String -> [String] 
splitByDelimiter = unfoldr . splitSingle 

splitSingle :: Char -> String -> Maybe (String,String) 
splitSingle _ [] = Nothing 
splitSingle delimiter xs = 
    let (ys, zs) = break (== delimiter) xs in 
    Just (ys, drop 1 zs) 

凡功能splitSingle分裂名单在第一个分隔符的两个子串中。

例如: "1,2,-5,-23,15" -> Just ("1", "2,-5,-23,15")

7

只是为了好玩,这里是你如何创建一个简单的解析器使用秒差距:

module Main where 

import Control.Applicative hiding (many) 
import Text.Parsec 
import Text.Parsec.String 

line :: Parser [Int] 
line = number `sepBy` (char ',' *> spaces) 

number = read <$> many digit 

一个优点是,它很容易地创建一个解析器是在什么灵活它将接受:

*Main Text.Parsec Text.Parsec.Token> :load "/home/mikste/programming/Temp.hs" 
[1 of 1] Compiling Main    (/home/mikste/programming/Temp.hs, interpreted) 
Ok, modules loaded: Main. 
*Main Text.Parsec Text.Parsec.Token> parse line "" "1, 2, 3" 
Right [1,2,3] 
*Main Text.Parsec Text.Parsec.Token> parse line "" "10,2703, 5, 3" 
Right [10,2703,5,3] 
*Main Text.Parsec Text.Parsec.Token> 
22
splitBy delimiter = foldr f [[]] 
      where f c [email protected](x:xs) | c == delimiter = []:l 
          | otherwise = (c:x):xs 

编辑:不是由原作者,但下面是一个更多(过分?)详细和灵活性较差的版本(具体到Char/String),以帮助澄清如何工作。使用上述版本是因为它适用于任何使用Eq实例的类型列表。

splitBy :: Char -> String -> [String] 
splitBy _ "" = []; 
splitBy delimiterChar inputString = foldr f [""] inputString 
    where f :: Char -> [String] -> [String] 
     f currentChar [email protected](partialString:handledStrings) 
      | currentChar == delimiterChar = "":allStrings -- start a new partial string at the head of the list of all strings 
      | otherwise = (currentChar:partialString):handledStrings -- add the current char to the partial string 

-- input:  "a,b,c" 
-- fold steps: 
-- first step: 'c' -> [""] -> ["c"] 
-- second step: ',' -> ["c"] -> ["","c"] 
-- third step: 'b' -> ["","c"] -> ["b","c"] 
-- fourth step: ',' -> ["b","c"] -> ["","b","c"] 
-- fifth step: 'a' -> ["","b","c"] -> ["a","b","c"] 
2
splitBy del str = helper del str [] 
    where 
     helper _ [] acc = let acc0 = reverse acc in [acc0] 
     helper del (x:xs) acc 
      | x==del = let acc0 = reverse acc in acc0 : helper del xs [] 
      | otherwise = let acc0 = x : acc  in helper del xs acc0 
1

此代码工作正常 用途: - 分裂 “你的字符串”[]与任何分隔符来替换 ''

split [] t = [t] 
split (a:l) t = if a==',' then (t:split l []) else split l (t++[a]) 
1
import qualified Text.Regex as RegExp 

myRegexSplit :: String -> String -> [String] 
myRegexSplit regExp theString = 
    let result = RegExp.splitRegex (RegExp.mkRegex regExp) theString 
    in filter (not . null) result 

-- using regex has the advantage of making it easy to use a regular 
-- expression instead of only normal strings as delimiters. 

-- the splitRegex function tends to return an array with an empty string 
-- as the last element. So the filter takes it out 

-- how to use in ghci to split a sentence 
let timeParts = myRegexSplit " " "I love ponies a lot"