Как разделить строку в Haskell?
есть ли стандартный способ разделить строку в Haskell?
lines и words отлично работает от разбиения на пробел или новую строку, но, конечно, есть стандартный способ разбить на запятую? Я не мог найти его в Хугле?
чтобы быть конкретным, я ищу что-то где split "," "my,comma,separated,list" возвращает ["my","comma","separated","list"]
спасибо.
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