After digging around a bit, I found subRegex in regex-compat. While this works well, it does not use PCRE, and as far as I can tell, there's no support for ByteStrings.
Grrr.
Anyhow, I took the subRegex implementation from regex-compat and mangled it slightly to work with Text.Regex.PCRE. I also added the (=~$) function which feels a bit more familiar to perl users. For example:
Prelude PCRESub> "me boo" =~$ ("(me) boo", "he \\1")
"he me"The above is equivalent to perl's:$text = "me boo"; $text =~ s/(me) boo/he $1/;(~=$) is implemented with reSub (which is also exported by PCRESub). reSub allows you to provide your own CompOption and ExecOption options.
Here's the PCRESub module:
-- PCRE-based Regex Substitution
-- Mohit Muthanna Cheppudira
--
-- Based off code by Chris Kuklewicz from regex-compat library.
--
-- Requires Text.Regex.PCRE from regex-pcre.
module PCRESub(
  (=~$),
  reSub
) where
import Data.Array((!))
import Text.Regex.PCRE
subRegex :: Regex                          -- ^ Search pattern
         -> String                         -- ^ Input string
         -> String                         -- ^ Replacement text
         -> String                         -- ^ Output string
subRegex _ "" _ = ""
subRegex regexp inp repl =
  let compile _i str [] = \ _m ->  (str++)
      compile i str (("\\",(off,len)):rest) =
        let i' = off+len
            pre = take (off-i) str
            str' = drop (i'-i) str
        in if null str' then \ _m -> (pre ++) . ('\\':)
             else \  m -> (pre ++) . ('\\' :) . compile i' str' rest m
      compile i str ((xstr,(off,len)):rest) =
        let i' = off+len
            pre = take (off-i) str
            str' = drop (i'-i) str
            x = read xstr
        in if null str' then \ m -> (pre++) . ((fst (m!x))++)
             else \ m -> (pre++) . ((fst (m!x))++) . compile i' str' rest m
      compiled :: MatchText String -> String -> String
      compiled = compile 0 repl findrefs where
        bre = makeRegexOpts defaultCompOpt execBlank "\\\\(\\\\|[0-9]+)"
        findrefs = map (\m -> (fst (m!1),snd (m!0))) (matchAllText bre repl)
      go _i str [] = str
      go i str (m:ms) =
        let (_,(off,len)) = m!0
            i' = off+len
            pre = take (off-i) str
            str' = drop (i'-i) str
        in if null str' then pre ++ (compiled m "")
             else pre ++ (compiled m (go i' str' ms))
  in go 0 inp (matchAllText regexp inp)
-- Substitue re with sub in str using options copts and eopts.
reSub :: String -> String -> String -> CompOption -> ExecOption -> String
reSub str re sub copts eopts = subRegex (makeRegexOpts copts eopts re) str sub
-- Substitute re with sub in str, e.g.,
--
-- The perl expression:
--
--   $text = "me boo";
--   $text =~ s/(me) boo/he $1/;
--
-- can be written as:
--
--   text = "me boo" =~$ ("(me) boo", "he \\1")
--
(=~$) :: String -> (String, String) -> String
(=~$) str (re, sub) = reSub str re sub defaultCompOpt defaultExecOptExample usage:import PCRESub
main = do
  let text = "me boo" =~$ ("(me) boo", "he \\1")
  print textPaste this code in, or browse the source at my GitHub repo: PCRESub.hsSomeone please make this work across all the regex backends (and add support for ByteStrings)!
s/haskell/perl/g
ReplyDelete:p
This is awesome. I'll be using VexFlow for displaying music Notes on my blog http://readmusic.org
ReplyDeleteAny manual/guide/tutorial available to make a posting in blog?
Thanks so much.
In haskell, you write your own substitution routine to fit your particular needs.
ReplyDeleteSee http://stackoverflow.com/questions/3847475/haskell-regex-substitution/3928438#3928438