在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.Text
的strip
和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
软件包带有一个strip
function:
import Data.String.Utils myString = " foo bar " -- strip :: String -> String myTrimmedString = strip myString -- myTrimmedString == "foo bar"
所以如果从String
到Text
的转换并没有在你的情况下有意义,你可以使用上面的函数。