una separar recortar quitar primeros primer palabra net los letras extraer espacios ejemplos caracteres caracter cadena string haskell trim removing-whitespace

string - recortar - separar palabra en letras c#



En Haskell, ¿cómo se recorta el espacio en blanco desde el principio y el final de una cuerda? (12)

¿Cómo se recorta el espacio en blanco desde el inicio y el final de una cadena?

trim " abc " => "abc"

Editar:

Ok, déjame ser un poco más claro. No entendí que los literales de las cadenas se trataran de forma tan diferente a Strings.

Me gustaría hacer esto:

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

¿Es esto posible en Haskell? Estoy usando -XOverloadedStrings pero parece que solo funciona para literales.



Después de que se hizo esta pregunta (alrededor del año 2012), Data.List obtuvo dropWhileEnd haciendo esto mucho más fácil:

trim = dropWhileEnd isSpace . dropWhile isSpace


En la línea de lo que otras personas han sugerido, puede evitar tener que invertir la cadena utilizando:

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


Esto debería ser correcto sobre O (n), creo:

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


Hoy en día, el paquete MissingH envía con una función de strip :

import Data.String.Utils myString = " foo bar " -- strip :: String -> String myTrimmedString = strip myString -- myTrimmedString == "foo bar"

Entonces, si la conversión de String a Text y viceversa no tiene sentido en su situación, podría usar la función anterior.


Ineficiente pero fácil de entender y pegar donde sea necesario:

strip = lstrip . rstrip lstrip = dropWhile (`elem` " /t") rstrip = reverse . lstrip . reverse


No sé nada sobre el tiempo de ejecución o la eficiencia, pero ¿qué pasa con esto?

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

Una solución sin usar ningún otro módulo o biblioteca que el Preludio.

Algunas pruebas:

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

Podría ser el tiempo de ejecución O (n).

Pero en realidad no lo sé porque no sé los tiempos de ejecución de las funciones e init. ;)


Otra solución (estándar)

import System.Environment import Data.Text strip :: String -> IO String strip = return . unpack . Data.Text.strip . pack main = getLine >>= Main.strip >>= putStrLn


Por supuesto, Data.Text es mejor para el rendimiento. Pero, como se mencionó, es divertido hacerlo con listas. Aquí hay una versión de que rstrip es la cadena en un solo paso (sin reverse y ++) y admite listas infinitas:

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 como para listas infinitas, eso funcionará:

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

y, por una razón obvia, eso no (se ejecutará para siempre):

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


Puede combinar la strip Data.Text con sus funciones un / packing para evitar tener cadenas sobrecargadas:

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

Probándolo:

> let s = " hello " > strip s "hello" > lstrip s "hello " > rstrip s " hello"


Sé que esta es una publicación anterior, pero no vi soluciones que implementaran el buen viejo fold .

Primero tira el espacio en blanco dropWhile usando dropWhile . Luego, usando foldl'' y un cierre simple, puede analizar el resto de la cadena en una sola pasada y, en base a ese análisis, pasar ese parámetro informativo para take , sin necesidad 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''

La variable c realiza un seguimiento de los espacios en blanco y no en blanco combinados que deben ser absorbidos, y la variable w realiza un seguimiento del espacio en blanco del lado derecho para ser eliminado.

Ejecuciones de prueba:

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

Salida:

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


Si tiene necesidades serias de procesamiento de texto, use el paquete de text de hackage:

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

Si eres demasiado terco para usar el text y no te gusta la ineficacia del método inverso, quizás (y me refiero a QUIZÁ) algo como el siguiente sea más eficiente:

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 .."

Escribí esto en el supuesto de que la longitud de los espacios sería mínima, por lo que su O (n) de ++ y reverse es de poca importancia. Pero una vez más, siento la necesidad de decir que si realmente está preocupado por el rendimiento, entonces no debería usar String en absoluto, vaya a Text .

EDITAR mi punto, un benchmark de Criterion rápido me dice que (para una cadena de palabras especialmente larga con espacios y ~ 200 espacios previos y posteriores) mi recorte requiere 1.6 ms, el recorte con inversión toma 3.5ms y Data.Text.strip toma 0.0016 ms ...