61

文字列の最初と最後から空白をどのようにトリミングしますか?

trim "  abc " 

=>

"abc"

編集:

わかりました、もう少し明確にしましょう。文字列リテラルが文字列とそれほど異なって扱われることを私は理解していませんでした。

私はこれをしたいと思います:

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

これはHaskellで可能ですか?-XOverloadedStringsを使用していますが、これはリテラルに対してのみ機能するようです。

4

13 に答える 13

63

深刻なテキスト処理のニーズがある場合は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ください。

私の主張を編集すると、簡単なCriterionベンチマークは、(スペースと約200の前後のスペースを持つ特に長い単語の文字列の場合)トリムに1.6ミリ秒、リバースを使用したトリムに3.5ミリ秒、 Data.Text.strip0.0016ミリ秒かかることを示しています。 。

于 2011-06-07T19:12:50.353 に答える
43

差出人:http ://en.wikipedia.org/wiki/Trim_ (programming)#Haskell

import Data.Char (isSpace)

trim :: String -> String
trim = f . f
   where f = reverse . dropWhile isSpace
于 2011-06-07T19:08:55.627 に答える
38

この質問が行われた後(2012年頃)、これがはるかに簡単になりましたData.ListdropWhileEnd

trim = dropWhileEnd isSpace . dropWhile isSpace
于 2016-07-09T14:57:03.313 に答える
15

非効率的ですが、理解しやすく、必要な場所に貼り付けることができます。

strip = lstrip . rstrip
lstrip = dropWhile (`elem` " \t")
rstrip = reverse . lstrip . reverse
于 2011-07-07T18:20:21.073 に答える
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)

ps無限リストに関しては、それは機能します:

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

そして、明らかな理由で、それはしません(永遠に実行されます):

List.length $ List.take n $ rstrip $ 'a':(cycle " ")
于 2014-01-16T05:55:42.693 に答える
3

Data.Textstripをアン/パック関数と組み合わせて、文字列のオーバーロードを回避できます。

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"
于 2014-02-26T10:18:10.390 に答える
3

現在、パッケージには次の機能MissingHが付属しています。strip

import           Data.String.Utils

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

したがって、StringtoTextとbackの変換が状況に合わない場合は、上記の関数を使用できます。

于 2017-11-03T14:03:21.077 に答える
1

これが古い投稿であることは知っていますが、古き良き実装を実装したソリューションは見当たりませんでしたfold

まず、を使用して先頭の空白を削除しdropWhileます。次に、foldl'と単純なクロージャを使用して、1回のパスで文字列の残りの部分を分析し、その分析に基づいて、その有益なパラメータをに渡すことができ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"
于 2014-04-13T09:05:37.177 に答える
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
于 2014-11-16T01:43:25.370 に答える
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 == ' ')

プレリュード以外のモジュールやライブラリを使用しないソリューション。

いくつかのテスト:

>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のランタイムがわからないので、実際にはわかりません。;)

于 2012-09-21T10:51:50.813 に答える
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
于 2013-12-13T07:25:02.250 に答える
0

trim派手なパッケージをインポートせずに独自の関数を実装したい場合。

import Data.Char (isSpace)

trimLeft :: String -> String
trimLeft = dropWhile isSpace

trimRight :: String -> String
trimRight = dropWhileEnd isSpace

trim :: String -> String
trim = trimRight . trimLeft
于 2021-07-09T14:55:47.130 に答える
-2

別の(標準)ソリューション

import System.Environment
import Data.Text

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

main = getLine >>= Main.strip >>= putStrLn
于 2014-05-03T12:53:43.933 に答える