String 在功能上用分隔符拆分字符串的最佳方法是什么?

String 在功能上用分隔符拆分字符串的最佳方法是什么?,string,haskell,split,String,Haskell,Split,我试着用Haskell编写程序,该程序将获取由逗号分隔的整数字符串,将其转换为整数列表,并将每个数字递增1 比如说 “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 ge

我试着用Haskell编写程序,该程序将获取由逗号分隔的整数字符串,将其转换为整数列表,并将每个数字递增1

比如说
“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
导入数据。列表
main::IO()
main=do
n字符串
getList n=foldr(++)[]。散布[分隔符]$replicate n inputStr
分隔符=','
inputStr=“1,2,-5,-23,15”
splitByDelimiter::Char->String->[String]
splitByDelimiter''=[]
splitByDelimiter分隔符列表=
映射(takeWhile(/=分隔符).tail)
(筛选器(isPrefixOf[分隔符])
(尾巴
(分隔符:列表)))
toInt::字符串->整型
toInt=读取
对我来说,最困难的部分是编写函数
splitByDelimiter
,它接受字符串并返回字符串列表

“1,2,-5,-23,15”->[“1”、“2”、“5”、“23”、“15”]

虽然它在工作,但我对它的书写方式并不满意。有很多括号,所以看起来像Lisp。此外,该算法有些人为:

  • 将分隔符前置到字符串的开头
    ”,1,2,-5,-23,15“

  • 生成所有尾部的列表
    [“,1,2,-5,-23,15”,“1,2,-5,-23,15”,“2,2,-5,-23,15”,…]

  • 筛选并仅保留以分隔符
    [“,1,2,-5,-23,15”,“,2,-5,-23,15”,…]开头的字符串。

  • 删除第一个分隔符并使用符号,直到满足下一个分隔符的要求

  • 因此,问题是:

    如何改进函数
    splitByDelimiter

    我是否可以删除分隔符的前置和删除,并直接拆分字符串

    如何重写函数以减少括号


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

    不能做到这一点吗?

    这有点像黑客,但见鬼,它可以工作

    yourFunc str = map (+1) $ read ("[" ++ str ++ "]")
    
    这是一个非黑客版本,使用
    unfover

    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
    

    这是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) splitByDelimiter::Char->String->[String] splitByDelimiter=展开符。分裂的 splitSingle::Char->String->Maybe(String,String) splitSingle[]=无 拆分单个分隔符xs= 让(ys,zs)=在中打断(=分隔符)xs 仅(Y,下降1 Z) 其中,函数splitSingle通过第一个分隔符将列表拆分为两个子字符串

    例如:
    “1,2,-5,-23,15”->只是(“1,2,-5,-23,15”)
    只是为了好玩,下面是如何使用Parsec创建一个简单的解析器:

    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
    
    编辑:不是由原作者编写的,但下面是一个更(过于?)详细、更不灵活的版本(特定于
    Char
    /
    String
    ),有助于澄清这是如何工作的。使用上述版本,因为它适用于具有
    Eq
    实例的类型的任何列表

    splitBy :: Char -> String -> [String]
    splitBy _ "" = [];
    splitBy delimiterChar inputString = foldr f [""] inputString
      where f :: Char -> [String] -> [String]
            f currentChar allStrings@(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"]
    
    这个代码很好用 用法:-拆分“您的字符串”[]并用任何分隔符替换“,”

    split [] t = [t]
    split (a:l) t = if a==',' then (t:split l []) else split l (t++[a])
    

    另一个没有进口的国家:

    splitBy :: Char -> String -> [String]
    splitBy _ [] = []
    splitBy c s  =
      let
        i = (length . takeWhile (/= c)) s
        (as, bs) = splitAt i s
      in as : splitBy c (if bs == [] then [] else tail bs)
    

    虽然这个软件包不是基本安装(Haskell平台)的一部分,但我认为它往往会被忽略。谢谢。它正是我所需要的。
    splitOneOf
    通常是一个更有用的函数,特别是当您需要考虑任意空格时。谢谢。这是一个很好的观点。我喜欢这里使用展开器的方式。在ghci:)中,在我的comp上,您的拆分速度比splitOn快43纳秒。此拆分函数的实现与您预期的工作方式不同-它无法正确拆分末尾带有逗号的字符串-缺少一个“”。如果要确保拆分函数100%可用,则应在分隔字符串的所有排列中插入相同的分隔符,例如“a、b、c”。
    foldr(++)[]
    也称为
    concat
    putStrLn。“显示”
    另称为“打印”。而且,
    n这个可能的复制品很精彩;我花了很长时间才理解它是如何工作的,但我喜欢它。虽然它对空字符串不起作用,也就是说,它的计算结果是
    [”“]
    ,而不是
    []
    。我同意@ljedrz的说法-我花了很长时间才理解它,但它太棒了!我希望您不介意,但我在您的答案中添加了一个不太灵活但非常详细的附录,以帮助其他人了解正在发生的事情。这是一个小小的吹毛求疵,但这是我所期望的
    splitOn
    函数的功能,而不是
    splitBy
    。对于
    splitBy
    我希望
    splitBy fn=foldr f[[]]其中f c l@(x:xs)=bool((c:x):xs)([]:l)$fn c
    ,当前的
    splitOn c
    功能由
    splitOn c=splitBy(=c)
    次要恢复,但可以使用
    many1
    number=read many1位
    中的
    来读取无效输入“1,2”产生一个左值,而不是Prelude.read中的异常。使用
    length
    是一种反模式(破坏惰性),使用
    span
    /
    break
    代替;
    (如果bs=[]那么[]否则尾bs)
    =
    drop 1 bs
    。在右侧添加重复的单例是一种反模式(导致二次行为)。
    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 
    
    split [] t = [t]
    split (a:l) t = if a==',' then (t:split l []) else split l (t++[a])
    
    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"
    
    splitBy :: Char -> String -> [String]
    splitBy _ [] = []
    splitBy c s  =
      let
        i = (length . takeWhile (/= c)) s
        (as, bs) = splitAt i s
      in as : splitBy c (if bs == [] then [] else tail bs)