Как разделить строку в Haskell?



есть ли стандартный способ разделить строку в Haskell?



lines и words отлично работает от разбиения на пробел или новую строку, но, конечно, есть стандартный способ разбить на запятую? Я не мог найти его в Хугле?



чтобы быть конкретным, я ищу что-то где split "," "my,comma,separated,list" возвращает ["my","comma","separated","list"]



спасибо.

985   12  

12 ответов:

есть пакет для этого называется сплит.

cabal install split

используйте его так:

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

Он поставляется с большим количеством других функций для разделения на соответствующие разделители или несколько разделителей.

помните, что вы можете посмотреть определение функций прелюдии!

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

глядя туда, определение words есть

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

Итак, измените его для функции, которая принимает предикат:

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

тогда назовите его с любым предикатом вы хотите!

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

Если вы используете данные.Текст, есть сплитон:

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

это встроено в платформу Haskell.

например:

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

или:

{-# LANGUAGE OverloadedStrings #-}

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

в тексте модуля.Регулярное выражение (часть платформы Haskell), есть функция:

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

, который разбивает строку на основе регулярного выражения. API можно найти по адресу Hackage.

использовать Data.List.Split, который использует split:

[me@localhost]$ 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]

попробуй это:

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

работает только для одного символа, но должен быть легко расширяемым.

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

например.

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

один конечный разделитель будет удален:

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

Я начал изучать Haskell вчера, так что поправьте меня, если я ошибаюсь, но:

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)

выдает:

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

или, может быть, вы хотели

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

что будет:

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)

Я не знаю, как добавить комментарий к ответу Стива, но я хотел бы рекомендовать
   документация библиотек GHC,
а там конкретно то
  функции Подсписка в данных.Список

что гораздо лучше в качестве ссылки, чем просто читать отчет равнины Хаскелл.

В общем случае, складка с правилом о том, когда создавать новый подсписок для подачи, также должна решить эту проблему.

в дополнение к эффективным и предварительно построенным функциям, приведенным в ответах, я добавлю свои собственные, которые являются просто частью моего репертуара функций Haskell, которые я писал, чтобы выучить язык в свое время:

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

решения являются по крайней мере хвост-рекурсивными, поэтому они не будут вызывать переполнение стека.

пример в ghci:

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

без импорта ничего прямая замена одного символа для пробела, целевой разделитель для words - это пространство. Что-то вроде:

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

или

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

вы можете сделать это в функцию с параметрами. Вы можете исключить параметр символ к матчу мой соответствие многим, как в:

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

Comments

    Ничего не найдено.