如何从字符串的开头和结尾修剪空格?
trim " abc "
=>
"abc"
编辑:
好的,让我更清楚一点。我不明白字符串文字的处理方式与字符串不同。
我想这样做:
import qualified Data.Text as T
let s :: String = " abc "
in T.strip s
Haskell有可能吗?我正在使用-XOverloadedStrings,但这似乎只适用于文字。
答案 0 :(得分:55)
如果您有严格的文本处理需求,请使用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 .."
我是在假设空间的长度最小的情况下写的,所以++
和reverse
的O(n)几乎没什么问题。但我觉得有必要说,如果你真的关心性能,那么你根本不应该使用String
- 转移到Text
。
答案 1 :(得分:34)
来自:http://en.wikipedia.org/wiki/Trim_(programming)#Haskell
import Data.Char (isSpace)
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
答案 2 :(得分:22)
在提出这个问题后(大约在2012年)Data.List
得到dropWhileEnd
使这更容易:
trim = dropWhileEnd isSpace . dropWhile isSpace
答案 3 :(得分:15)
效率低但易于理解并粘贴到需要的地方:
strip = lstrip . rstrip
lstrip = dropWhile (`elem` " \t")
rstrip = reverse . lstrip . reverse
答案 4 :(得分:3)
当然,Data.Text更适合性能。但是,如前所述,使用列表进行操作会很有趣。这是一个版本,rstrip是单个传递中的字符串(没有反向和++)并且支持无限列表:
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)
P.S。对于无限列表,这将起作用:
List.length $ List.take n $ rstrip $ cycle "abc "
并且,由于显而易见的原因,这将不会(将永远运行):
List.length $ List.take n $ rstrip $ 'a':(cycle " ")
答案 5 :(得分:3)
您可以将Data.Text
的{{1}}与其un / packing函数结合使用,以避免重载字符串:
strip
测试它:
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
答案 6 :(得分:3)
现在MissingH
包附带strip
函数:
import Data.String.Utils
myString = " foo bar "
-- strip :: String -> String
myTrimmedString = strip myString
-- myTrimmedString == "foo bar"
因此,如果从String
转换为Text
并返回在您的情况下没有意义,则可以使用上述函数。
答案 7 :(得分:1)
我知道这是一篇旧帖子,但是我没有看到任何能够实现好fold
的解决方案。
首先使用dropWhile
去除前导空白区域。然后,使用foldl'
和一个简单的闭包,您可以在一次传递中分析字符串的其余部分,并根据该分析将该信息参数传递给take
,而不需要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'
变量c
跟踪应该被吸收的组合白色和非白色空间,变量w
跟踪要剥离的右侧白色空间。
测试运行:
print $ trim " a b c "
print $ trim " ab c "
print $ trim " abc "
print $ trim "abc"
print $ trim "a bc "
输出:
"a b c"
"ab c"
"abc"
"abc"
"a bc"
答案 8 :(得分:1)
对于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
答案 9 :(得分:0)
我对运行时或效率一无所知但是这个:
-- 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之外的任何其他模块或库的解决方案。
一些测试:
>lrtrim ""
>""
>lrtrim " "
>""
>lrtrim "haskell "
>"haskell"
>lrtrim " haskell "
>"haskell"
>lrtrim " h a s k e ll "
>"h a s k e ll"
它可能是运行时O(n)。
但实际上我不知道它,因为我不知道函数last和init的运行时间。 ;)
答案 10 :(得分:0)
根据其他人的建议,您可以避免使用以下方法来反转字符串:
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
答案 11 :(得分:0)
如果您想在不导入任何花哨的包的情况下实现自己的 trim
函数。
import Data.Char (isSpace)
trimLeft :: String -> String
trimLeft = dropWhile isSpace
trimRight :: String -> String
trimRight = dropWhileEnd isSpace
trim :: String -> String
trim = trimRight . trimLeft
答案 12 :(得分:-1)
另一个(标准)解决方案
import System.Environment
import Data.Text
strip :: String -> IO String
strip = return . unpack . Data.Text.strip . pack
main = getLine >>= Main.strip >>= putStrLn