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.
De: http://en.wikipedia.org/wiki/Trim_(programming)#Haskell
import Data.Char (isSpace)
trim :: String -> String
trim = f . f
where f = reverse . dropWhile isSpace
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 ...