source

하스켈에서 줄을 쪼개는 방법은?

ittop 2023. 10. 4. 22:56
반응형

하스켈에서 줄을 쪼개는 방법은?

하스켈에서 줄을 분할하는 표준 방법이 있습니까?

lines그리고.words공간이나 새로운 선에서 분할하는 것으로부터 훌륭한 일을 하지만, 확실히 쉼표에서 분할하는 표준적인 방법이 있습니까?

후글에서 찾을 수가 없었어요.

구체적으로 말씀드리면, 제가 찾고 있는 것은split "," "my,comma,separated,list"돌아온다["my","comma","separated","list"].

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"

스플릿이라고 불리는 이 패키지가 있습니다.

cabal install split

다음과 같이 사용합니다.

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

일치하는 구분자를 분할하거나 여러 구분자를 사용할 수 있는 다른 많은 기능들과 함께 제공됩니다.

데이터를 사용하는 경우.텍스트, splitOn이 있습니다.

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

이것은 하스켈 플랫폼에 구축되어 있습니다.

예를 들어 다음과 같습니다.

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"

사용하다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]

공백에 대해 한 문자를 직접 대체하는 것 없이 대상 구분자를 가져옵니다.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"

이것을 매개변수가 있는 함수로 만들 수 있습니다.다음과 같이 matching multi-matching multi-matching 매개변수를 제거할 수 있습니다.

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

Text(텍스트) 모듈에서.레젝스(Haskell Platform의 일부)에는 다음과 같은 기능이 있습니다.

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

정규식을 기반으로 문자열을 분할합니다.API는 Hackage에서 확인할 수 있습니다.

이것을 시도해 보십시오.

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"]

이해하기 쉬운 점은 다음과 같습니다.

split :: Char -> String -> [String]
split c xs = case break (==c) xs of 
  (ls, "") -> [ls]
  (ls, x:rs) -> ls : split c rs

어제부터 해스켈을 배우기 시작했는데 틀리면 고쳐주세요.

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 라이브러리 설명서,
그리고 거기에 구체적으로.
  데이터의 서브리스트 기능.목록.

그냥 평범한 하스켈 보고서를 읽는 것보다 참고가 훨씬 낫습니다.

일반적으로 새 하위 목록을 생성할 시기에 대한 규칙이 있는 접기도 이를 해결해야 합니다.

ghci의 예:

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

답변에 주어진 효율적이고 미리 구축된 기능 외에 제가 직접 언어를 배우기 위해 쓰고 있던 하스켈 기능 레퍼토리의 일부인 제 자신의 기능을 추가하겠습니다.

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

솔루션은 적어도 스택 오버플로가 발생하지 않도록 테일 리커시브(tail-recursive) 기능을 갖추고 있습니다.

많이 늦었지만 관심 있는 분들을 위해 여기에 추가하고 싶습니다. 포장에 의존하지 않고 간단한 해결책을 찾고 계신다면,

split :: String -> String -> [String]
split _ "" = []
split delim str =
  split' "" str []
  where
    dl = length delim

    split' :: String -> String -> [String] -> [String]
    split' h t f
      | dl > length t = f ++ [h ++ t]
      | delim == take dl t = split' "" (drop dl t) (f ++ [h])
      | otherwise = split' (h ++ take 1 t) (drop 1 t) f

답이 너무 많은데 다 마음에 안 들어요.해스켈은 잘 모르지만, 5분 동안 훨씬 더 짧게 그리고 (생각대로) 더 깨끗한 버전을 썼습니다.

splitString :: Char -> [Char] -> [[Char]]
splitString _ [] = []
splitString sep str = 
    let (left, right) = break (==sep) str 
    in left : splitString sep (drop 1 right)

언급URL : https://stackoverflow.com/questions/4978578/how-to-split-a-string-in-haskell

반응형