2011-02-12 75 views
122

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

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

Para ser más específicos, estoy buscando algo donde split "," "my,comma,separated,list" vuelve ["my","comma","separated","list"]

Gracias.

+14

Realmente me gustaría que a tal función en una versión futura de '' Data.List' o incluso Prelude'. Es tan común y desagradable si no está disponible para code-golf. – fuz

+0

¡Esto está separado! –

Respuesta

109

Hay un paquete para esto llamado split.

cabal install split 

utilizar de esta manera:

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

Viene con una gran cantidad de otras funciones para la división en la coincidencia de los delimitadores o tener varios delimitadores.

+8

Cool. No estaba al tanto de este paquete. Este es * el * último paquete dividido ya que da mucho control sobre la operación (recortar espacio en los resultados, dejar separadores en el resultado, eliminar separadores consecutivos, etc.). Hay tantas formas de dividir listas, que no es posible tener una sola función de "división" que responda a todas las necesidades, realmente necesita ese tipo de paquete. – gawi

+1

de lo contrario, si los paquetes externos son aceptables, MissingH también proporciona una función dividida: http://hackage.haskell.org/packages/archive/MissingH/1.2.0.0/doc/html/Data-List-Utils.html#v:split Ese paquete también proporciona muchas otras funciones "agradables para tener" y creo que bastantes paquetes dependen de ello. –

+29

El paquete dividido ahora está separado de la plataforma haskell a partir de la versión más reciente. –

9

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 

sólo funciona para un solo char, pero debería ser fácilmente extensible.

17

En el Text.Regex módulo (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.

137

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

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

Buscando 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' 

Así, cambiarla por una función que toma un predicado:

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

Entonces llamarlo con cualquier predicado ¡usted quiere!

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

No sé cómo agregar un comentario a la respuesta de Steve, pero me gustaría recomendar la
    GHC libraries documentation,
y de allí específicamente la
    Sublist functions in Data.List

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

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

5

empecé a aprender Haskell ayer, por lo que me corrija si estoy equivocado, pero:

split :: Eq a => a -> [a] -> [[a]] 
split x y = func x y [[]] 
    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ían

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

que sería :

splitWithStr :: Eq a => [a] -> [a] -> [[a]] 
splitWithStr x y = func x y [[]] 
    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) 
+0

que estaba buscando un 'split' incorporado, se echa a perder por idiomas con bibliotecas bien desarrollados. Pero gracias de cualquier manera. –

+3

escribiste esto en junio, así que supongo que se ha movido en en su viaje :) Como ejercicio, intentando volver a escribir esta función sin inversa o longitud que el uso de estas funciones una sanción por la complejidad algorítmica y también evitar la aplicación a una lista infinita divertirse! –

22

Si utiliza data.text, no es splitOn:

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

Este se construye en la Plataforma Haskell.

Así, 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" 
+0

data.text importación no funciona – RussAbbott

+0

@RussAbbott probable que necesita para una dependencia del paquete 'Text' o instalarlo. Sin embargo, pertenecería a otra pregunta. –

11

Uso Data.List.Split, que utiliza split:

[[email protected]]$ ghci 
Prelude> import Data.List.Split 
Prelude Data.List.Split> let l = splitOn "," "1,2,3,4" 
Prelude Data.List.Split> :t l 
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] 
+0

importar Data.List.Split no funciona – RussAbbott

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

P. ej

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

Un delimitador de arrastre solo será dado de baja:

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

Además de las funciones eficientes y pre-construidos que figuran en las respuestas Voy a añadir mi propia que son simplemente parte de mi repertorio de Haskell funciones que estaba escribiendo para aprender el idioma en mi tiempo libre:

-- Correct but inefficient implementation 
wordsBy :: String -> Char -> [String] 
wordsBy s c = 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 s f = 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 recursiva de cola para que no se incurrirá en un desbordamiento de pila.

2

en el Ejemplo ghci:

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