【问题标题】:Cutting a string into a list in Haskell?在Haskell中将字符串切割成列表?
【发布时间】:2011-08-17 23:47:48
【问题描述】:

是否可以剪切字符串例如

"one , Two"

到一个列表

["one", "two"]

或者只是

"one", "two"

谢谢

【问题讨论】:

    标签: string list haskell


    【解决方案1】:

    如果您不想安装split package (see Frerich Raabe's answer),这里有一个splitOn 函数的实现,它对依赖关系很轻:

    import Data.List
    
    splitOn :: Eq a => [a] -> [a] -> [[a]]
    splitOn []    _  = error "splitOn: empty delimiter"
    splitOn delim xs = loop xs
        where loop [] = [[]]
              loop xs | delim `isPrefixOf` xs = [] : splitOn delim (drop len xs)
              loop (x:xs) = let (y:ys) = splitOn delim xs
                             in (x:y) : ys
              len = length delim
    

    【讨论】:

      【解决方案2】:

      这里常规的旧列表操作就足够了,

      import Data.Char
      
      > [ w | w <- words "one , Two", all isAlpha w ]
      ["one","Two"]
      

      又名

      > filter (all isAlpha) . words $ "one , Two"
      ["one","Two"]
      

      列表黑客、解析和设计

      在文本处理中存在一定程度的权力和权重。在最简单的情况下,基于列表的解决方案,例如上面的解决方案,提供非常少的句法噪音,以获得快速的结果(与 shell 脚本中的快速'n'dirty 文本处理相同)。

      列表操作可能会变得非常复杂,您可能会考虑,例如通用的split 库,用于在任意文本上拆分列表,

      > splitOn " , " "one , Two"
      ["one","Two"]
      

      对于更难的问题,或不太可能被丢弃的代码,更强大的技术是有意义的。特别是,您可以通过使用解析器组合器将问题描述为语法来避免脆弱的模式匹配,例如parsecuu-parsinglib。随着时间的推移,通过解析器描述的字符串处理往往会导致代码更加健壮,因为随着需求的变化,修改以组合器样式编写的解析器相对容易。

      关于正则表达式的注意事项:列表匹配和正则表达式在易用性和(不)安全性方面大致相同,因此出于讨论的目的,您可以用“正则表达式”代替“列表拆分”。如果代码打算长期存在,解析几乎总是正确的方法。

      【讨论】:

      • +1,但是......对于像"one |, Two" -&gt; ["one |", "Two"] 这样的情况呢? (例如,不要使用包含非分隔符)
      • 问题未明确。
      • 承认 :-) 但是如果有一个解决方案能够涵盖我的测试用例,例如Haskell 中是否有一个惯用的“string.split”等价物? (或者通过动态序列匹配对任何列表进行更一般的拆分)。
      • 添加了一些关于字符串破解方法的讨论。
      【解决方案3】:

      有一个完整的函数模块用于不同的策略来拆分列表(例如字符串,它只是一个字符列表):Data.List.Split

      使用这个,你可以做到

      import Data.List.Split
      
      > splitOn " , " "one , Two"
      ["one","Two"]
      

      【讨论】:

      • 由于某种原因我没有那个要导入
      • @Tom:Haskell 平台默认没有安装它。但是,您可以使用cabal install split 安装它。
      【解决方案4】:

      未经测试,使用 Parsec。可能还有一个正则表达式分隔符。

      firstElement :: Parser String
      firstElement = many $ noneOf ' '
      
      otherElement :: Parser String
      otherElement = do many $ char ' '
                        char ','
                        many $ char ' '
                        firstElement
      
      elements :: Parser [String]
      elements = liftM2 (:) firstElement (many otherElement)
      
      parseElements :: String -> [String]
      parseElements = parse elements "(unknown)"
      

      以某种方式清理otherElement 会很好,类似于我使用liftM2 设法折叠elements

      【讨论】:

        猜你喜欢
        • 2022-09-27
        • 1970-01-01
        • 2017-06-18
        • 1970-01-01
        • 2022-01-21
        • 2020-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多