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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 01:07:49  来源:igfitidea点击:

In Haskell, how do you trim whitespace from the beginning and end of a string?

stringhaskelltrimremoving-whitespace

提问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 textpackage from hackage:

如果您有严重的文本处理需求,请使用text来自 hackage的软件包:

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

If you're too stubborn to use textand 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 reverseis 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 Stringat 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.striptakes 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.Listgot dropWhileEndmaking 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 stripwith 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 MissingHpackage ships with a stripfunction:

如今,该MissingH软件包附带了一个strip功能:

import           Data.String.Utils

myString = "    foo bar    "
-- strip :: String -> String
myTrimmedString = strip myString
-- myTrimmedString == "foo bar"

So if the conversion from Stringto Textand back does not make sense in your situation, you could use the function above.

因此,如果从StringtoText和 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 ckeeps track of combined white and non white-space that should be absorbed, and variable wkeeps 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 函数的运行时。;)