string 在 Haskell 中,如何修剪字符串开头和结尾的空格?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6270324/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In Haskell, how do you trim whitespace from the beginning and end of a string?
提问by Eric Normand
How do you trim whitespace from the start and end of a string?
如何从字符串的开头和结尾修剪空格?
trim " abc "
=>
"abc"
Edit:
编辑:
Ok, let me be a little clearer. I did not understand that string literals were treated so differently from Strings.
好吧,让我说得更清楚一点。我不明白字符串文字与字符串的处理方式如此不同。
I would like to do this:
我想这样做:
import qualified Data.Text as T
let s :: String = " abc "
in T.strip s
Is this possible in Haskell? I am using -XOverloadedStrings but that appears only to work for literals.
这在 Haskell 中可能吗?我正在使用 -XOverloadedStrings 但这似乎只适用于文字。
回答by Thomas M. DuBuisson
If you have serious text processing needs then use the text
package from hackage:
如果您有严重的文本处理需求,请使用text
来自 hackage的软件包:
> :set -XOverloadedStrings
> import Data.Text
> strip " abc "
"abc"
If you're too stubborn to use text
and don't like the inefficiency of the reverse method then perhaps (and I mean MAYBE) something like the below will be more efficient:
如果你太固执text
而不能使用并且不喜欢反向方法的低效率,那么也许(我的意思是可能)像下面这样的东西会更有效:
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 .."
I wrote this on the assumption that the length of spaces would be minimal, so your O(n) of ++
and reverse
is of little concern. But once again I feel the need to say that if you actually are concerned about the performance then you shouldn't be using String
at all - move to Text
.
我写这篇文章的假设是空格的长度是最小的,所以你的 O(n)++
和reverse
几乎没有关系。但是我再次感到有必要说,如果您确实关心性能,那么您根本不应该使用String
- 移至Text
.
EDIT making my point, a quick Criterion benchmark tells me that (for a particularly long string of words with spaces and ~200 pre and post spaces) my trim takes 1.6 ms, the trim using reverse takes 3.5ms, and Data.Text.strip
takes 0.0016 ms...
编辑说明了我的观点,一个快速的标准基准告诉我(对于一串特别长的带有空格和~200 个前后空格的单词)我的修剪需要 1.6 毫秒,使用反向修剪需要 3.5Data.Text.strip
毫秒,并且需要 0.0016 毫秒。 .
回答by Eric Normand
From: http://en.wikipedia.org/wiki/Trim_(programming)#Haskell
来自:http: //en.wikipedia.org/wiki/Trim_(programming)#Haskell
import Data.Char (isSpace)
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
回答by spopejoy
After this question was asked (circa 2012) Data.List
got dropWhileEnd
making this a lot easier:
这个问题被问(大约2012)后,Data.List
得到了dropWhileEnd
使这是一个容易得多:
trim = dropWhileEnd isSpace . dropWhile isSpace
回答by Simon Michael
Inefficient but easy to understand and paste in where needed:
低效但易于理解并粘贴在需要的地方:
strip = lstrip . rstrip
lstrip = dropWhile (`elem` " \t")
rstrip = reverse . lstrip . reverse
回答by wonder.mice
For sure, Data.Text is better for performance. But, as was mentioned, it's just fun to do it with lists. Here is a version that rstrip's the string in single pass (without reverse and ++) and supports infinite lists:
当然,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. as for infinite lists, that will work:
ps至于无限列表,这将起作用:
List.length $ List.take n $ rstrip $ cycle "abc "
and, for obvious reason, that will not (will run forever):
并且,出于显而易见的原因,这不会(将永远运行):
List.length $ List.take n $ rstrip $ 'a':(cycle " ")
回答by John J. Camilleri
You can combine Data.Text
's strip
with it's un/packing functions to avoid having overloaded strings:
您可以将Data.Text
'sstrip
与它的 un/packing 函数结合使用,以避免重载字符串:
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 it:
测试它:
> let s = " hello "
> strip s
"hello"
> lstrip s
"hello "
> rstrip s
" hello"
回答by Damian Nadales
Nowadays the MissingH
package ships with a strip
function:
如今,该MissingH
软件包附带了一个strip
功能:
import Data.String.Utils
myString = " foo bar "
-- strip :: String -> String
myTrimmedString = strip myString
-- myTrimmedString == "foo bar"
So if the conversion from String
to Text
and back does not make sense in your situation, you could use the function above.
因此,如果从String
toText
和 back的转换在您的情况下没有意义,您可以使用上面的函数。
回答by Arild
This should be right about O(n), I believe:
这应该是关于 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
回答by eazar001
I know this is an old post, but I saw no solutions that implemented good old fold
.
我知道这是一篇旧帖子,但我没有看到实施 good old 的解决方案fold
。
First strip the leading white-space using dropWhile
. Then, using foldl'
and a simple closure, you can analyze the rest of the string in one pass, and based on that analysis, pass that informative parameter to take
, without needing reverse
:
首先使用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'
Variable c
keeps track of combined white and non white-space that should be absorbed, and variable w
keeps track of right side white-space to be stripped.
变量c
跟踪应该被吸收的组合空白和非空白,变量w
跟踪要剥离的右侧空白。
Test Runs:
测试运行:
print $ trim " a b c "
print $ trim " ab c "
print $ trim " abc "
print $ trim "abc"
print $ trim "a bc "
Output:
输出:
"a b c"
"ab c"
"abc"
"abc"
"a bc"
回答by jimmyt
I don't know anything about the runtime or efficiency but what about this:
我对运行时或效率一无所知,但是这个呢:
-- 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 == ' ')
A solution without using any other module or library than the Prelude.
除了 Prelude 之外,不使用任何其他模块或库的解决方案。
Some tests:
一些测试:
>lrtrim ""
>""
>lrtrim " "
>""
>lrtrim "haskell "
>"haskell"
>lrtrim " haskell "
>"haskell"
>lrtrim " h a s k e ll "
>"h a s k e ll"
It could be runtime O(n).
它可能是运行时 O(n)。
But I actually don't know it because I don't know the runtimes of the functions last and init. ;)
但实际上我不知道,因为我不知道 last 和 init 函数的运行时。;)