replacement / substition with Haskell regex libraries

时光怂恿深爱的人放手 提交于 2020-12-28 06:55:07

问题


Is there a high-level API for doing search-and-replace with regexes in Haskell? In particular, I'm looking at the Text.Regex.TDFA or Text.Regex.Posix packages. I'd really like something of type:

f :: Regex -> (ResultInfo -> m String) -> String -> m String

so, for example, to replace "dog" with "cat" you could write

runIdentity . f "dog" (return . const "cat")    -- :: String -> String

or do more advanced things with the monad, like counting occurrences, etc.

Haskell documentation for this is pretty lacking. Some low-level API notes are here.


回答1:


How about the subRegex in package Text.Regex?

Prelude Text.Regex> :t subRegex
subRegex :: Regex -> String -> String -> String

Prelude Text.Regex> subRegex (mkRegex "foo") "foobar" "123"
"123bar"



回答2:


I don't know of any existing function that creates this functionality, but I think that I'd end up using something like the AllMatches [] (MatchOffset, MatchLength) instance of RegexContent to simulate it:

replaceAll :: RegexLike r String => r -> (String -> String) -> String -> String
replaceAll re f s = start end
  where (_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s
        go (ind,read,write) (off,len) =
          let (skip, start) = splitAt (off - ind) read 
              (matched, remaining) = splitAt len matched 
          in (off + len, remaining, write . (skip++) . (f matched ++))

replaceAllM :: (Monad m, RegexLike r String) => r -> (String -> m String) -> String -> m String
replaceAllM re f s = do
  let go (ind,read,write) (off,len) = do
      let (skip, start) = splitAt (off - ind) read 
      let (matched, remaining) = splitAt len matched 
      replacement <- f matched
      return (off + len, remaining, write . (skip++) . (replacement++))
  (_, end, start) <- foldM go (0, s, return) $ getAllMatches $ match re s
  start end



回答3:


Based on @rampion's answer, but with the typo fixed so it doesn't just <<loop>>:

replaceAll :: Regex -> (String -> String) -> String -> String
replaceAll re f s = start end
  where (_, end, start) = foldl' go (0, s, id) $ getAllMatches $ match re s
        go (ind,read,write) (off,len) =
            let (skip, start) = splitAt (off - ind) read 
                (matched, remaining) = splitAt len start 
            in (off + len, remaining, write . (skip++) . (f matched ++))



回答4:


maybe this approach fit you.

import Data.Array (elems)
import Text.Regex.TDFA ((=~), MatchArray)

replaceAll :: String -> String -> String -> String        
replaceAll regex new_str str  = 
    let parts = concat $ map elems $ (str  =~  regex :: [MatchArray])
    in foldl (replace' new_str) str (reverse parts) 

  where
     replace' :: [a] -> [a] -> (Int, Int) -> [a]
     replace' new list (shift, l)   = 
        let (pre, post) = splitAt shift list
        in pre ++ new ++ (drop l post)



回答5:


You can use replaceAll from the Data.Text.ICU.Replace module.

Prelude> :set -XOverloadedStrings
Prelude> import Data.Text.ICU.Replace
Prelude Data.Text.ICU.Replace> replaceAll "cat" "dog" "Bailey is a cat, and Max is a cat too."
"Bailey is a dog, and Max is a dog too."



回答6:


For doing “search-and-replace” with “more advanced things with the monad, like counting occurrences, etc,” I recommend Replace.Megaparsec.streamEditT.

See the package README for specific examples of how to count occurrences.



来源:https://stackoverflow.com/questions/9071682/replacement-substition-with-haskell-regex-libraries

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!