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