haskell regex substitution

后端 未结 3 976
我寻月下人不归
我寻月下人不归 2020-12-15 16:38

Despite the ridiculously large number of regex matching engines for Haskell, the only one I can find that will substitute is Text.Regex, which

相关标签:
3条回答
  • 2020-12-15 17:22

    I don't think "just roll your own" is a reasonable answer to people trying to get actual work done, in an area where every other modern language has a trivial way to do this. Including Scheme. So here's some actual resources; my code is from a project where I was trying to replace "qql foo bar baz qq" with text based on calling a function on the stuff inside the qq "brackets", because reasons.

    Best option: pcre-heavy:

          let newBody = gsub [re|\s(qq[a-z]+)\s(.*?)\sqq\s|] (unWikiReplacer2 titles) body in do
    [snip]
    unWikiReplacer2 :: [String] -> String -> [String] -> String
    unWikiReplacer2 titles match subList = case length subList > 0 of
            True -> " --" ++ subList!!1 ++ "-- "
            False -> match
    

    Note that pcre-heavy directly supports function-based replacement, with any string type. So nice.

    Another option: pcre-light with a small function that works but isn't exactly performant:

        let newBody = replaceAllPCRE "\\s(qq[a-z]+)\\s(.*?)\\sqq\\s" (unWikiReplacer titles) body in do
    [snip]
    unWikiReplacer :: [String] -> (PCRE.MatchResult String) -> String
    unWikiReplacer titles mr = case length subList > 0 of
            True -> " --" ++ subList!!1 ++ "-- "
            False -> PCRE.mrMatch mr
        where
            subList = PCRE.mrSubList mr
    
    -- A very simple, very dumb "replace all instances of this regex
    -- with the results of this function" function.  Relies on the
    -- MatchResult return type.
    --
    -- https://github.com/erantapaa/haskell-regexp-examples/blob/master/RegexExamples.hs
    -- was very helpful to me in constructing this
    --
    -- I also used
    -- https://github.com/jaspervdj/hakyll/blob/ea7d97498275a23fbda06e168904ee261f29594e/src/Hakyll/Core/Util/String.hs
    replaceAllPCRE :: String              -- ^ Pattern
               -> ((PCRE.MatchResult String) -> String)  -- ^ Replacement (called on capture)
               -> String              -- ^ Source string
               -> String              -- ^ Result
    replaceAllPCRE pattern f source =
        if (source PCRE.=~ pattern) == True then
          replaceAllPCRE pattern f newStr
        else
          source
        where
            mr = (source PCRE.=~ pattern)
            newStr = (PCRE.mrBefore mr) ++ (f mr) ++ (PCRE.mrAfter mr)
    

    Someone else's fix: http://0xfe.blogspot.com/2010/09/regex-substitution-in-haskell.html

    Another one, this time embedded in a major library: https://github.com/jaspervdj/hakyll/blob/master/src/Hakyll/Core/Util/String.hs

    Another package for this purpose: https://hackage.haskell.org/package/pcre-utils

    0 讨论(0)
  • 2020-12-15 17:30

    Update 2020

    I totally agree with @rlpowell that

    I don't think "just roll your own" is a reasonable answer to people trying to get actual work done, in an area where every other modern language has a trivial way to do this.

    At the time of this writing, there is also Regex.Applicative.replace for regex substitution, though it's not Perl-compatible.

    For pattern-matching and substitution with parsers instead of regex, there is Replace.Megaparsec.streamEdit

    0 讨论(0)
  • 2020-12-15 17:35

    The regular expression API in regex-base is generic to the container of characters to match. Doing some kind of splicing generically to implements substitution would be very hard to make efficient. I did not want to provide a crappy generic routine.

    Writing a small function to do the substitution exactly how you want is just a better idea, and it can be written to match your container.

    0 讨论(0)
提交回复
热议问题