在Haskell中,如何从string的开头和结尾修剪空格?

如何从string的开始和结尾修剪空格?

trim " abc " => "abc" 

编辑:

好吧,让我更清楚一点。 我不明白string文字与string是如此不同的。

我想这样做:

 import qualified Data.Text as T let s :: String = " abc " in T.strip s 

这在Haskell中可能吗? 我正在使用-XOverloadedStrings,但似乎只适用于文字。

如果您有严重的文本处理需求,则使用hackage中的text包:

 > :set -XOverloadedStrings > import Data.Text > strip " abc " "abc" 

如果你太固执地使用text并且不喜欢反向方法的低效率,那么或许(也就是说,可能是MAYBE)类似下面的东西会更有效率:

 import Data.Char trim xs = dropSpaceTail "" $ dropWhile isSpace xs dropSpaceTail maybeStuff "" = "" dropSpaceTail maybeStuff (x:xs) | isSpace x = dropSpaceTail (x:maybeStuff) xs | null maybeStuff = x : dropSpaceTail "" xs | otherwise = reverse maybeStuff ++ x : dropSpaceTail "" xs > trim " hello this \t should trim ok.. .I think .. \t " "hello this \t should trim ok.. .I think .." 

我是这样写的,假设空格的长度是最小的,所以你的O(n) ++reverse是不重要的。 但是我又觉得有必要说,如果你真的关心性能,那么你根本就不应该使用String – 移动到Text

编辑使我的观点,一个快速的标准基准testing告诉我(对于一个特别长的空格string和~200前后空格)我的修剪需要1.6毫秒,修剪使用反向需要3.5ms, Data.Text.strip需要0.0016 ms …

来自: http : //en.wikipedia.org/wiki/Trim_(programming)#Haskell

 import Data.Char (isSpace) trim :: String -> String trim = f . f where f = reverse . dropWhile isSpace 

效率低下但易于理解并粘贴在需要的地方:

 strip = lstrip . rstrip lstrip = dropWhile (`elem` " \t") rstrip = reverse . lstrip . reverse 

这个问题之后被问(大约2012年) Data.List得到dropWhileEnd使这容易很多:

 trim = dropWhileEnd isSpace . dropWhile isSpace 

当然,Data.Text性能更好。 但是,正如前面提到的那样,使用列表来实现这一点很有趣。 这是一个版本,rstrip的单通(不带反向和++)的string,并支持无限列表:

 rstrip :: String -> String rstrip str = let (zs, f) = go str in if f then [] else zs where go [] = ([], True) go (y:ys) = if isSpace y then let (zs, f) = go ys in (y:zs, f) else (y:(rstrip ys), False) 

PS无限列表,这将工作:

 List.length $ List.take n $ rstrip $ cycle "abc " 

而且,由于显而易见的原因,这不会(将永远运行):

 List.length $ List.take n $ rstrip $ 'a':(cycle " ") 

你可以结合Data.Textstrip和un / packing函数来避免重载string:

 import qualified Data.Text as T strip = T.unpack . T.strip . T.pack lstrip = T.unpack . T.stripStart . T.pack rstrip = T.unpack . T.stripEnd . T.pack 

testing它:

 > let s = " hello " > strip s "hello" > lstrip s "hello " > rstrip s " hello" 

我知道这是一个旧的post,但我没有看到解决scheme实现了良好的旧fold

首先使用dropWhile前导空格。 然后,使用foldl'和一个简单的闭包,你可以在一遍中分析剩余的string,并根据这个分析,传递这个信息参数,而不需要reverse

 import Data.Char (isSpace) import Data.List (foldl') trim :: String -> String trim s = let s' = dropWhile isSpace s trim' = foldl' (\(c,w) x -> if isSpace x then (c,w+1) else (c+w+1,0)) (0,0) s' in take (fst trim') s' 

variablesc跟踪应该被吸收的组合的白色和非白色空间,并且variablesw跟踪右侧白色空间被剥离。

testing运行:

 print $ trim " abc " print $ trim " ab c " print $ trim " abc " print $ trim "abc" print $ trim "a bc " 

输出:

 "abc" "ab c" "abc" "abc" "a bc" 

我对运行时间或效率一无所知,但这又如何呢?

 -- entirely input is to be trimmed trim :: String -> String trim = Prelude.filter (not . isSpace') -- just the left and the right side of the input is to be trimmed lrtrim :: String -> String lrtrim = \xs -> rtrim $ ltrim xs where ltrim = dropWhile (isSpace') rtrim xs | Prelude.null xs = [] | otherwise = if isSpace' $ last xs then rtrim $ init xs else xs -- returns True if input equals ' ' isSpace' :: Char -> Bool isSpace' = \c -> (c == ' ') 

没有使用任何其他模块或库比Prelude的解决scheme。

一些testing:

 >lrtrim "" >"" >lrtrim " " >"" >lrtrim "haskell " >"haskell" >lrtrim " haskell " >"haskell" >lrtrim " haske ll " >"haske ll" 

它可能是运行时O(n)。

但是我其实并不知道,因为我不知道函数last和init的运行时间。 ;)

按照其他人的build议,可以避免使用下列方法来反转string:

 import Data.Char (isSpace) dropFromTailWhile _ [] = [] dropFromTailWhile p item | p (last items) = dropFromTailWhile p $ init items | otherwise = items trim :: String -> String trim = dropFromTailWhile isSpace . dropWhile isSpace 

另一个(标准)解决scheme

 import System.Environment import Data.Text strip :: String -> IO String strip = return . unpack . Data.Text.strip . pack main = getLine >>= Main.strip >>= putStrLn 

这应该是正确的关于O(N),我相信:

 import Data.Char (isSpace) trim :: String -> String -- Trimming the front is easy. Use a helper for the end. trim = dropWhile isSpace . trim' [] where trim' :: String -> String -> String -- When finding whitespace, put it in the space bin. When finding -- non-whitespace, include the binned whitespace and continue with an -- empty bin. When at the end, just throw away the bin. trim' _ [] = [] trim' bin (a:as) | isSpace a = trim' (bin ++ [a]) as | otherwise = bin ++ a : trim' [] as 

现在MissingH软件包带有一个stripfunction:

 import Data.String.Utils myString = " foo bar " -- strip :: String -> String myTrimmedString = strip myString -- myTrimmedString == "foo bar" 

所以如果从StringText的转换并没有在你的情况下有意义,你可以使用上面的函数。