66 votes

En Haskell, comment couper les espaces blancs du début et de la fin d'une chaîne de caractères ?

Comment couper les espaces blancs au début et à la fin d'une chaîne de caractères ?

trim "  abc " 

=>

"abc"

Edit :

Ok, laissez-moi être un peu plus clair. Je n'avais pas compris que les littéraux de chaîne étaient traités si différemment des chaînes de caractères.

J'aimerais le faire :

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

Est-ce possible en Haskell ? J'utilise -XOverloadedStrings mais cela ne semble fonctionner que pour les littéraux.

3voto

wonder.mice Points 1333

Il est certain que Data.Text est plus performant. Mais, comme il a été mentionné, c'est juste amusant de le faire avec des listes. Voici une version qui rstrip la chaîne en une seule passe (sans reverse et ++) et qui supporte les listes infinies :

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. quant aux listes infinies, cela fonctionnera :

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

et, pour des raisons évidentes, cela ne fonctionnera pas (fonctionnera éternellement) :

List.length $ List.take n $ rstrip $ 'a':(cycle " ")

3voto

Damian Nadales Points 2024

Aujourd'hui, le MissingH est livré avec un strip fonction :

import           Data.String.Utils

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

Donc si la conversion de String a Text et arrière n'a pas de sens dans votre situation, vous pouvez utiliser la fonction ci-dessus.

1voto

eazar001 Points 761

Je sais que c'est un vieux post, mais je n'ai vu aucune solution qui implémente le bon vieux fold .

Supprimez d'abord les espaces blancs de tête en utilisant dropWhile . Ensuite, en utilisant foldl' et d'une simple fermeture, vous pouvez analyser le reste de la chaîne en une seule fois et, sur la base de cette analyse, transmettre ce paramètre informatif à la commande take sans avoir besoin de 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 garde la trace des espaces blancs et non blancs combinés qui devraient être absorbés, et les variables w garde la trace de l'espace blanc du côté droit qui doit être supprimé.

Test Runs :

print $ trim "      a   b c    "
print $ trim "      ab c    "
print $ trim "    abc    "
print $ trim "abc"
print $ trim "a bc    "

Sortie :

"a   b c"
"ab c"
"abc"
"abc"
"a bc"

1voto

Arild Points 106

Cela devrait être à peu près O(n), je crois :

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

0voto

jimmyt Points 171

Je ne sais rien de la durée d'exécution ou de l'efficacité, mais qu'en est-il de ceci :

-- 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 == ' ')

Une solution sans utiliser aucun autre module ou bibliothèque que le Prelude.

Quelques tests :

>lrtrim ""
>""

>lrtrim "       "
>""

>lrtrim "haskell       "
>"haskell"

>lrtrim "      haskell       "
>"haskell"

>lrtrim "     h  a  s k e   ll       "
>"h  a  s k e   ll"

Le temps d'exécution pourrait être de O(n).

Mais en fait, je ne le sais pas car je ne connais pas les temps d'exécution des fonctions last et init. ;)

0 votes

Les deux sont O(n), bien que init ait au moins un facteur de deux sur le dernier, puisqu'il copie n - 1 éléments. Utilisez Data.Text pour ce genre de choses. Créer vos propres fonctions Prelude est facile, amusant et lent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X