¿Cómo dividir una cadena en Haskell?

¿Hay una forma estándar de dividir una cadena en Haskell?

lines y las words funcionan bien si se dividen en un espacio o línea nueva, pero seguramente hay una forma estándar de dividir en una coma. No pude encontrarlo en Hoogle?

Para ser específico, estoy buscando algo donde split "," "my,comma,separated,list" devuelve ["my","comma","separated","list"]

Gracias.

Hay un paquete para esto llamado split .

 cabal install split 

Úselo así:

 ghci> import Data.List.Split ghci> splitOn "," "my,comma,separated,list" ["my","comma","separated","list"] 

Viene con muchas otras funciones para dividir en delimitadores coincidentes o tener varios delimitadores.

¡Recuerde que puede buscar la definición de funciones de Prelude!

http://www.haskell.org/onlinereport/standard-prelude.html

Mirando allí, la definición de words es,

 words :: String -> [String] words s = case dropWhile Char.isSpace s of "" -> [] s' -> w : words s'' where (w, s'') = break Char.isSpace s' 

Por lo tanto, cámbielo por una función que tenga un predicado:

 wordsWhen :: (Char -> Bool) -> String -> [String] wordsWhen ps = case dropWhile ps of "" -> [] s' -> w : wordsWhen p s'' where (w, s'') = break ps' 

¡Entonces llámalo con el predicado que quieras!

 main = print $ wordsWhen (==',') "break,this,string,at,commas" 

Si usa Data.Text, hay splitOn:

http://hackage.haskell.org/packages/archive/text/0.11.2.0/doc/html/Data-Text.html#v:splitOn

Esto está construido en la plataforma Haskell.

Entonces, por ejemplo:

 import qualified Data.Text as T main = print $ T.splitOn (T.pack " ") (T.pack "this is a test") 

o:

 {-# LANGUAGE OverloadedStrings #-} import qualified Data.Text as T main = print $ T.splitOn " " "this is a test" 

En el módulo Text.Regex (parte de la Plataforma Haskell), hay una función:

 splitRegex :: Regex -> String -> [String] 

que divide una cadena basada en una expresión regular. La API se puede encontrar en Hackage .

Use Data.List.Split , que usa split :

 [me@localhost]$ ghci Prelude> import Data.List.Split Prelude Data.List.Split> let l = splitOn "," "1,2,3,4" Prelude Data.List.Split> :tl l :: [[Char]] Prelude Data.List.Split> l ["1","2","3","4"] Prelude Data.List.Split> let { convert :: [String] -> [Integer]; convert = map read } Prelude Data.List.Split> let l2 = convert l Prelude Data.List.Split> :t l2 l2 :: [Integer] Prelude Data.List.Split> l2 [1,2,3,4] 

Prueba este:

 import Data.List (unfoldr) separateBy :: Eq a => a -> [a] -> [[a]] separateBy chr = unfoldr sep where sep [] = Nothing sep l = Just . fmap (drop 1) . break (== chr) $ l 

Solo funciona para un solo char, pero debe poder extenderse fácilmente.

 split :: Eq a => a -> [a] -> [[a]] split d [] = [] split ds = x : split d (drop 1 y) where (x,y) = span (/= d) s 

P.ej

 split ';' "a;bb;ccc;;d" > ["a","bb","ccc","","d"] 

Se eliminará un único delimitador final:

 split ';' "a;bb;ccc;;d;" > ["a","bb","ccc","","d"] 

Empecé a aprender Haskell ayer, así que corrígeme si estoy equivocado pero:

 split :: Eq a => a -> [a] -> [[a]] split xy = func xy [[]] where func x [] z = reverse $ map (reverse) z func x (y:ys) (z:zs) = if y==x then func x ys ([]:(z:zs)) else func x ys ((y:z):zs) 

da:

 *Main> split ' ' "this is a test" ["this","is","a","test"] 

o tal vez querías

 *Main> splitWithStr " and " "this and is and a and test" ["this","is","a","test"] 

cuál podría ser:

 splitWithStr :: Eq a => [a] -> [a] -> [[a]] splitWithStr xy = func xy [[]] where func x [] z = reverse $ map (reverse) z func x (y:ys) (z:zs) = if (take (length x) (y:ys)) == x then func x (drop (length x) (y:ys)) ([]:(z:zs)) else func x ys ((y:z):zs) 

No sé cómo agregar un comentario en la respuesta de Steve, pero me gustaría recomendar el
Documentación de las bibliotecas de GHC
y allí específicamente el
Funciones de sublista en Data.List

Lo cual es mucho mejor como referencia, que solo leer el informe simple de Haskell.

Genéricamente, un fold con una regla sobre cuándo crear una nueva sublista para alimentar, debería resolverlo también.

Además de las funciones eficientes y preconstruidas dadas en las respuestas, agregaré las mías que son simplemente parte de mi repertorio de funciones de Haskell que estaba escribiendo para aprender el idioma en mi propio tiempo:

 -- Correct but inefficient implementation wordsBy :: String -> Char -> [String] wordsBy sc = reverse (go s []) where go s' ws = case (dropWhile (\c' -> c' == c) s') of "" -> ws rem -> go ((dropWhile (\c' -> c' /= c) rem)) ((takeWhile (\c' -> c' /= c) rem) : ws) -- Breaks up by predicate function to allow for more complex conditions (\c -> c == ',' || c == ';') wordsByF :: String -> (Char -> Bool) -> [String] wordsByF sf = reverse (go s []) where go s' ws = case ((dropWhile (\c' -> f c')) s') of "" -> ws rem -> go ((dropWhile (\c' -> (f c') == False)) rem) (((takeWhile (\c' -> (f c') == False)) rem) : ws) 

Las soluciones son al menos recursivas de cola para que no incurran en un desbordamiento de stack.

Ejemplo en el ghci:

 > import qualified Text.Regex as R > R.splitRegex (R.mkRegex "x") "2x3x777" > ["2","3","777"] 

Sin importar nada una sustitución directa de un carácter por un espacio, el separador de destino para words es un espacio. Algo como:

 words [if c == ',' then ' ' else c|c <- "my,comma,separated,list"] 

o

 words let f ',' = ' '; fc = c in map f "my,comma,separated,list" 

Puede convertir esto en una función con parámetros. Puedes eliminar el parámetro carácter a coincidencia mis muchos coincidentes, como en:

  [if elem c ";,.:-+@!$#?" then ' ' else c|c <-"my,comma;separated!list"]