Как разбить строку в Haskell?
Есть ли стандартный способ разделить строку в Haskell?
lines
и words
отлично работают с расщеплением пространства или новой строки, но, конечно, есть стандартный способ разделить на запятую? Я не мог направить его в Hoogle?
Чтобы быть конкретным, я ищу что-то, где split "," "my,comma,separated,list"
возвращает ["my","comma","separated","list"]
Спасибо.
Ответы
Ответ 1
Существует пакет для этого split.
cabal install split
Используйте его следующим образом:
ghci> import Data.List.Split
ghci> splitOn "," "my,comma,separated,list"
["my","comma","separated","list"]
Он поставляется с множеством других функций для разделения на соответствующие разделители или с несколькими разделителями.
Ответ 2
Помните, что вы можете найти определение функций Prelude!
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"
Ответ 3
Если вы используете Data.Text, есть splitOn:
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"
Ответ 4
В модуле Text.Regex(часть платформы Haskell) есть функция:
splitRegex :: Regex -> String -> [String]
который разбивает строку на основе регулярного выражения. API можно найти в Hackage.
Ответ 5
Используйте Data.List.Split
, который использует 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]
Ответ 6
Попробуйте следующее:
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
Работает только для одного char, но его следует легко расширять.
Ответ 7
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"]
Ответ 8
Я не знаю, как добавить комментарий на ответ Стива, но я хотел бы рекомендовать
Документация библиотек GHC,
и там, в частности,
Функции подписок в Data.List
Это намного лучше, чем ссылка, чем просто чтение простого отчета Haskell.
В общем случае сбрасывание с правилом о том, когда нужно создать новый подсписок для подачи, также должно решить.
Ответ 9
Я начал изучать 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)
Ответ 10
Пример в ghci:
> import qualified Text.Regex as R
> R.splitRegex (R.mkRegex "x") "2x3x777"
> ["2","3","777"]
Ответ 11
В дополнение к эффективным и заранее построенным функциям, указанным в ответах, я добавлю свои собственные, которые являются частью моего репертуара функций 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)
Решения, по крайней мере, являются хвостовыми рекурсивными, поэтому они не будут нести переполнение стека.