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

如何从字符串的开头和结尾修剪空格?

trim "  abc " 

=>

"abc"

编辑:

好吧,让我说清楚一点。 我不明白字符串文字与字符串有何不同。

我想这样做:

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

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

12个解决方案
56 votes

如果您有严重的文本处理需求,请使用hackage的Data.Text.strip软件包:

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

如果您太顽固而不能使用Data.Text.strip并且不喜欢反向方法的低效率,那么也许(我的意思是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  .."

我是根据这样的假设写的,即空间的长度应最小,因此您对Data.Text.stripreverse的O(n)并不在意。 但是,我再次有必要说,如果您真正关心性能,那么您根本不应该使用String-转到Text

编辑我的观点是,一个快速的Criterion基准告诉我(对于带有空格以及〜200个前置和后置空格的特别长的字符串),我的修剪花费1.6毫秒,使用反向的修剪花费3.5ms,而Data.Text.strip花费0.0016毫秒。 ..

Thomas M. DuBuisson answered 2020-02-19T07:43:46Z
34 votes

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

import Data.Char (isSpace)

trim :: String -> String
trim = f . f
   where f = reverse . dropWhile isSpace
Eric Normand answered 2020-02-19T07:44:07Z
24 votes

提出此问题后(大约在2012年)Data.List得到了dropWhileEnd,这使操作变得容易得多:

trim = dropWhileEnd isSpace . dropWhile isSpace
spopejoy answered 2020-02-19T07:44:27Z
15 votes

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

strip = lstrip . rstrip
lstrip = dropWhile (`elem` " \t")
rstrip = reverse . lstrip . reverse
Simon Michael answered 2020-02-19T07:44:48Z
3 votes

当然,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)

ps。 至于无限列表,将起作用:

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

并且,由于明显的原因,这将不会(将永远运行):

List.length $ List.take n $ rstrip $ 'a':(cycle " ")
wonder.mice answered 2020-02-19T07:45:17Z
3 votes

您可以将Data.Textstrip与它的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

测试它:

> let s = "  hello  "
> strip s
"hello"
> lstrip s
"hello  "
> rstrip s
"  hello"
John J. Camilleri answered 2020-02-19T07:45:41Z
3 votes

如今String软件包附带String功能:

import           Data.String.Utils

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

因此,如果在您的情况下从StringTextText的转换没有意义,则可以使用上面的函数。

Damian Nadales answered 2020-02-19T07:46:05Z
1 votes

我知道这是一个旧帖子,但是我看不到任何解决方案都可以实现旧的c

首先使用c去除前导空格,然后使用w和一个简单的闭包,您可以一次性分析字符串的其余部分,然后基于该分析将该信息参数传递给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"
eazar001 answered 2020-02-19T07:46:43Z
1 votes

我相信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
Arild answered 2020-02-19T07:47:04Z
0 votes

我对运行时或效率一无所知,但对此:

-- 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的运行时。 ;)

jimmyt answered 2020-02-19T07:47:41Z
0 votes

按照其他人的建议,您可以避免使用以下方法来反转字符串:

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
sommnium003 answered 2020-02-19T07:48:01Z
-1 votes

另一个(std)解决方案

import System.Environment
import Data.Text

strip :: String -> IO String
strip = return . unpack . Data.Text.strip . pack

main = getLine >>= Main.strip >>= putStrLn
user3599138 answered 2020-02-19T07:48:24Z
translate from https://stackoverflow.com:/questions/6270324/in-haskell-how-do-you-trim-whitespace-from-the-beginning-and-end-of-a-string