replacement / substition with Haskell regex libraries

前端 未结 6 461
无人共我
无人共我 2021-02-04 01:20

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

相关标签:
6条回答
  • 2021-02-04 01:44

    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.

    0 讨论(0)
  • 2021-02-04 01:46

    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
    
    0 讨论(0)
  • 2021-02-04 01:51

    How about the Text.Regex.subRegex in package regex-compat?

    Prelude> import Text.Regex (mkRegex, subRegex)
    
    Prelude> :t mkRegex
    mkRegex :: String -> Regex
    
    Prelude> :t subRegex
    subRegex :: Regex -> String -> String -> String
    
    Prelude> subRegex (mkRegex "foo") "foobar" "123"
    "123bar"
    
    0 讨论(0)
  • 2021-02-04 01:56

    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)
    
    0 讨论(0)
  • 2021-02-04 02:01

    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."
    
    0 讨论(0)
  • 2021-02-04 02:09

    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 ++))
    
    0 讨论(0)
提交回复
热议问题