Haskellで文字列を分割する標準的な方法はありますか?
lines
そしてwords
スペースや改行で分割からの仕事の偉大な、しかし確実に、カンマで分割するための標準的な方法はありますか?
Hoogleでは見つかりませんでした。
具体的には、split "," "my,comma,separated,list"
戻ってくるところを探しています["my","comma","separated","list"]
。
Haskellで文字列を分割する標準的な方法はありますか?
lines
そしてwords
スペースや改行で分割からの仕事の偉大な、しかし確実に、カンマで分割するための標準的な方法はありますか?
Hoogleでは見つかりませんでした。
具体的には、split "," "my,comma,separated,list"
戻ってくるところを探しています["my","comma","separated","list"]
。
回答:
これにはsplitと呼ばれるパッケージがあります。
cabal install split
次のように使用します。
ghci> import Data.List.Split
ghci> splitOn "," "my,comma,separated,list"
["my","comma","separated","list"]
一致する区切り文字で分割するため、またはいくつかの区切り文字を持つための他の多くの関数が付属しています。
split
あります。すべてのニーズに応える単一の機能を持つことはできません。そのようなパッケージが本当に必要です。
split
しbuild-depends
ます。たとえば、プロジェクトがhelloの場合、hello.cabal
そのexecutable hello
行の下のファイルに「build-depends:base、split」のような行を挿入します(2つのスペースインデントに注意)。次に、cabal build
コマンドを使用してビルドします。Cf. haskell.org/cabal/users-guide/...
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"
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"
text
パッケージへの依存関係またはそれをインストールする必要があります。ただし、別の質問に属します。
Text.Regexモジュール(Haskellプラットフォームの一部)には、次の関数があります。
splitRegex :: Regex -> String -> [String]
正規表現に基づいて文字列を分割します。APIはHackageにあります。
Could not find module ‘Text.Regex’ Perhaps you meant Text.Read (from base-4.10.1.0)
以下を使用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]
スペースを1文字で直接置換したものを何もインポートしない場合、対象となるセパレーター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"]
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)
split
、よく開発されたライブラリーを備えた言語に甘やかされている組み込みのを探していました。とにかくありがとう。
Steveの回答にコメントを追加する方法はわかりませんが、
GHCライブラリのドキュメント、
特に
Data.ListのSublist関数をお勧めします
これは、単純なHaskellレポートを読むよりも、リファレンスとしてはるかに優れています。
一般的に、フィードする新しいサブリストをいつ作成するかに関するルールを備えた折り畳みも、それを解決するはずです。
回答で与えられた効率的で事前に構築された関数に加えて、自分の時間で言語を学ぶために書いていた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"]
ghci
ますか?
Data.List
またはの今後のリリースで、このような機能を本当に利用したいと考えていPrelude
ます。コードゴルフで利用できない場合、それはとても一般的で厄介です。