packages feed

regex-do 2.4 → 2.5

raw patch · 29 files changed

+930/−550 lines, 29 files

Files

changelog.md view
@@ -1,3 +1,9 @@+#####   2.5+  *API changes*+  split PCRE to Ascii and Utf8+  remove \[Comp\] opt from replace signature   +  tweak trim  + #####   2.4   refactor Replace: remove ReplaceCase. Use Once | All hints instead    
regex-do.cabal view
@@ -1,5 +1,5 @@ name:                regex-do-version:             2.4+version:             2.5 synopsis:            PCRE wrapper description:         format, search, replace (String | ByteString) with PCRE regex. Utf8-safe author:              Imants Cekusins@@ -19,23 +19,28 @@ library   exposed-modules:           Text.Regex.Do.Trim-          Text.Regex.Do.Pcre.Match           Text.Regex.Do.Pcre.Option-          Text.Regex.Do.Pcre.Replace+          Text.Regex.Do.Pcre.Utf8.Replace           Text.Regex.Do.Split           Text.Regex.Do.Format           Text.Regex.Do.Type.Do           Text.Regex.Do.Type.Reexport           Text.Regex.Do.Convert           Text.Regex.Do.Pad-          Text.Regex.Do.Pcre.MatchHint-          Text.Regex.Do.Pcre.ReplaceOpen+          Text.Regex.Do.Pcre.Ascii.MatchHint+          Text.Regex.Do.ReplaceOpen           Text.Regex.Do.Type.Extract-          Text.Regex.Do.Type.Regex_+          Text.Regex.Do.Type.Regex           Text.Regex.Do.Type.MatchHint-  other-modules:+          Text.Regex.Do.Pcre.Ascii.Match+          Text.Regex.Do.Pcre.Ascii.Replace+          Text.Regex.Do.Pcre.Utf8.Match+          Text.Regex.Do.Pcre.Utf8.MatchHint           Text.Regex.Do.Pcre.Matchf-          Text.Regex.Do.Pcre.Result++  other-modules:+          Text.Regex.Do.Result+   ghc-options:  -fwarn-unused-imports        build-depends:  base <= 5.0,@@ -58,6 +63,7 @@                         ConstraintKinds                         ScopedTypeVariables                         DeriveFunctor+                        TypeFamilies                          test-suite spec@@ -74,6 +80,7 @@                         ConstraintKinds                         ScopedTypeVariables                         DeriveFunctor+                        TypeFamilies     main-is: Main.hs@@ -84,6 +91,7 @@         TestRegex.TestSplit         TestRegex.TestTrim         TestRegex.TestReplaceOpen+        TestRegex.TestReplaceUtf    build-depends:  base <= 5.0,                   hspec,
src/Text/Regex/Do/Convert.hs view
@@ -13,6 +13,9 @@ toByteString::String -> ByteString toByteString = E.encodeUtf8 . T.pack +toByteString'::String -> Utf8_ ByteString+toByteString' = Utf8_ . toByteString+ -- | both Ascii and Utf8 toString::ByteString -> String toString = T.unpack . E.decodeUtf8
+ src/Text/Regex/Do/Pcre/Ascii/Match.hs view
@@ -0,0 +1,69 @@+{- | although sometimes funs in Ascii modules work with non-ascii text+    (as some examples show),+    for reliable results with Utf8 pattern or body,+    use "Text.Regex.Do.Pcre.Utf8.Match"++    see also "Text.Regex.Base.RegexLike" and "Text.Regex.Do.Pcre.Ascii.MatchHint" -}++module Text.Regex.Do.Pcre.Ascii.Match+    (Match(..),+    R.extract   -- | 'extract' is reexport from "Text.Regex.Base.RegexLike"+    ) where++import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Pcre.Matchf as F+import Text.Regex.PCRE.Wrap()+import Text.Regex.Do.Type.Regex+import Text.Regex.Do.Type.MatchHint+++{- | 'match' covers all result types++    compiler looks up the appropriate function depending on the result type++    '=~' is borrowed from "Text.Regex.PCRE.Wrap",+    is a short version of 'match'++    See also "Text.Regex.Do.Pcre.Ascii.MatchHint"       -}++class Match a b out where+    match::Pattern a -> Body b -> out+    (=~)::a     -- ^ pattern+        -> b    -- ^ body+        -> out+    (=~) p0 b0 = match (Pattern p0) (Body b0)+++-- | match once+instance Rx_ a b => Match a b [b] where+    match p0 = once (makeRegex' p0)+{- ^  >>> "^all" =~ "all the time"::[String]++     \["all"\]      -}+instance Rx_ a b => Match a b Bool where+    match p0 (Body b0) = R.matchTest (makeRegex p0) b0+{- ^ test++    >>> "в" =~ "тихо в лесу"::Bool++    True    -}++-- | match all+instance Rx_ a b => Match a b [[b]] where+    match p0 = F.all (makeRegex' p0)+{- ^  >>> "well" =~ "all is well that ends well"::[[ByteString]]++     \[["well"\],\["well"\]]        -}++-- | match once+instance Rx_ a b => Match a b [PosLen] where+    match p0 b0 = maybe [] id $ poslen_ (Once $ makeRegex' p0) b0+{- ^ >>> "à" =~ "tourner à gauche"::[PosLen]++     \[(8,2)\]      -}++-- | match all+instance Rx_ a b => Match a b [[PosLen]] where+    match p0 = poslen_ $ All $ makeRegex' p0+
+ src/Text/Regex/Do/Pcre/Ascii/MatchHint.hs view
@@ -0,0 +1,85 @@+{- | this module uses+    <https://cdepillabout.github.io/haskell-type-families-presentation/#/ TypeFamilies>++    this module is similar to "Text.Regex.Do.Pcre.Ascii.Match". The differences are:++    "Text.Regex.Do.Pcre.Ascii.Match" is more flexible:+        accepts 'Pattern' Regex,+        accepts 'Pattern' and 'Body' of different types++    "Text.Regex.Do.Pcre.Ascii.Match" needs to infer result type++    in this module the result type is determined by the hint+    -}++module Text.Regex.Do.Pcre.Ascii.MatchHint where++import Text.Regex.Do.Type.Do hiding (Once,All)+import Text.Regex.PCRE.Wrap()+import qualified Text.Regex.Do.Pcre.Ascii.Match as M+import Text.Regex.Do.Type.MatchHint+import Data.ByteString+++{- | picks 'M.Match' instance where 'Pattern' and 'Body' are of the same type++    'Hint' and inferrable 'Pattern' or 'Body' type determine the instance++    handy when working with 'OverloadedStrings', in other cases when compiler needs a hint  -}++++class (Hint hint, M.Match a a (F hint a)) =>+    MatchHint hint a where+    type F hint a+    match::hint (Pattern a) -> Body a -> F hint a+    match h0 = M.match $ unhint h0++    (=~)::hint a  -- ^ hint & pattern+            -> a          -- ^ body+            -> F hint a   -- ^ type defined by the instance, determined by the hint+    (=~) h0 = (M.=~) $ unhint h0+++instance MatchHint Test String where+    type F Test String = Bool+++instance MatchHint PosLen' String where+    type F PosLen' String = [PosLen]++{- ^ >>> PosLen' ("и"::String) =~ "бывает и хуже"++    \[(13,2)\]      -}++instance MatchHint PosLen_ String where+    type F PosLen_ String = [[PosLen]]++instance MatchHint Once String where+    type F Once String = [String]++{- ^ >>> Once ("^all"::String) =~ "all the time"++    \["all"\]       -}++instance MatchHint All String where+    type F All String = [[String]]++instance MatchHint Test ByteString where+    type F Test ByteString = Bool++{- ^ >>> Test ("в"::ByteString) =~ "тихо в лесу"++    True    -}++instance MatchHint PosLen' ByteString where+    type F PosLen' ByteString = [PosLen]++instance MatchHint PosLen_ ByteString where+    type F PosLen_ ByteString = [[PosLen]]++instance MatchHint Once ByteString where+    type F Once ByteString = [ByteString]++instance MatchHint All ByteString where+    type F All ByteString = [[ByteString]]
+ src/Text/Regex/Do/Pcre/Ascii/Replace.hs view
@@ -0,0 +1,79 @@+{- | === Ascii vs Utf8 modules++    for reliable results with Utf8 pattern or body,+    use "Text.Regex.Do.Pcre.Utf8.Replace"   -}++module Text.Regex.Do.Pcre.Ascii.Replace+    (Replace(..),+    Repl_)  where++import Text.Regex.Base.RegexLike as R+import Prelude as P+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Type.Reexport as R+import Text.Regex.Do.Pcre.Matchf+import qualified Text.Regex.Do.ReplaceOpen as O+import Text.Regex.Do.Type.Regex as T+import Text.Regex.Do.Type.Extract+import Text.Regex.Do.Type.MatchHint+import Text.Regex.Do.Pcre.Option as O+++class Replace all a repl b where+    replace::(R_ b, Matchf all b) =>+        all (Pattern a) -> repl b -> Body b -> b++type Repl_ f rx r a = (T.Regex rx,+                        R.RegexLike R.Regex a,+                        Extract' a,+                        O.ReplaceOpen f r)++replace_ fn0 p0 r0 b0 =+   let ma1 = fn0 p1 b0+       p1 = T.makeRegex' <$> p0+   in O.replace ma1 r0 b0++++instance Repl_ Maybe a repl b => Replace Once a repl b where+    replace = replace_ marray_++{- ^ === static replace for simple (no group) needle++    for no-regex 'ByteString' replacement see "Text.Regex.Do.Split"++    >>> replace (Once (Pattern "^a\\s")) (Replacement "A") (Body "a bc")++    \"Abc\"++   === dynamic group replace++    >>> replace (Once (Pattern "\\w=(\\d{1,3})")) replacer $ Body "a=101 b=3 12"++     "a=[1 0 1] b=3 12"     -}+++instance Repl_ [] a repl b => Replace All a repl b where+    replace = replace_ marray_+++{- ^ to tweak regex with 'O.Comp' or 'O.Exec', see "Text.Regex.Do.Type.Regex"++   === dynamic group replace++   custom replacer fn returns replacement value. See 'O.defaultReplacer'++   >>> replacer::GroupReplacer String+       replacer = defaultReplacer 1 tweak1+             where tweak1 str1 = case str1 of+                                   "101" -> "[1 0 1]"+                                   "3" -> "[ 3 ]"+                                   otherwise -> trace str1 "?"+++    >>> replace (All (Pattern "\\w=(\\d{1,3})")) replacer $ Body "a=101 b=3 12"++        "a=[1 0 1] b=[ 3 ] 12"      -}++dum_::Comp+dum_ = Blank
− src/Text/Regex/Do/Pcre/Match.hs
@@ -1,72 +0,0 @@--- | see "Text.Regex.Base.RegexLike" and "Text.Regex.Do.Pcre.MatchHint"-module Text.Regex.Do.Pcre.Match-    (Match(..),-    R.extract,   -- | 'extract' is reexport from "Text.Regex.Base.RegexLike"-    makeRegexOpts) where--import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)-import Text.Regex.Do.Type.Do-import Text.Regex.Do.Pcre.Matchf as F-import Text.Regex.PCRE.Wrap()-import Text.Regex.Do.Type.Regex_---{- | 'match' covers all result types--    compiler looks up the appropriate function depending on the result type--    '=~' is borrowed from "Text.Regex.PCRE.Wrap",-    is a short version of 'match'--    See also "Text.Regex.Do.Pcre.MatchHint"       -}--class Match a b out where-    match::Pattern a -> Body b -> out-    (=~)::a     -- ^ pattern-        -> b    -- ^ body-        -> out-    (=~) p0 b0 = match (Pattern p0) (Body b0)----- | match once-instance Rx_ a b => Match a b [b] where-    match = once-{- ^  >>> "^all" =~ "all the time"::[String]--     \["all"\]--     "Text.Regex.Do.Pcre.MatchHint"     -}-instance Rx_ a b => Match a b Bool where-    match p0 (Body b0) = R.matchTest (r_ p0) b0-{- ^ test--    >>> "в" =~ "тихо в лесу"::Bool--    True--    "Text.Regex.Do.Pcre.MatchHint"      -}---- | match all-instance Rx_ a b => Match a b [[b]] where-    match = F.all-{- ^  >>> "well" =~ "all is well that ends well"::[[ByteString]]--     \[["well"\],\["well"\]]--     "Text.Regex.Do.Pcre.MatchHint"    -}---- | match once-instance Rx_ a b => Match a b [PosLen] where-    match p0 b0 = maybe [] id $ poslen_ p0 b0-{- ^ >>> "и" =~ "бывает и хуже"::[PosLen]--     \[(13,2)\]--     /Utf8/--     "Text.Regex.Do.Pcre.MatchHint"     -}---- | match all-instance Rx_ a b => Match a b [[PosLen]] where-    match = poslen_-
− src/Text/Regex/Do/Pcre/MatchHint.hs
@@ -1,82 +0,0 @@-{- | this module uses-    <https://cdepillabout.github.io/haskell-type-families-presentation/#/ TypeFamilies>--    this module is similar to "Text.Regex.Do.Pcre.Match". The differences are:--    "Text.Regex.Do.Pcre.Match" is more flexible:-        accepts 'Pattern' Regex,-        accepts 'Pattern' and 'Body' of different types--    "Text.Regex.Do.Pcre.Match" needs to infer result type--    in this module the result type is determined by the hint-    -}--{-# LANGUAGE TypeFamilies #-}-module Text.Regex.Do.Pcre.MatchHint where--import Text.Regex.Do.Type.Do hiding (Once,All)-import Text.Regex.PCRE.Wrap()-import qualified Text.Regex.Do.Pcre.Match as M-import Text.Regex.Do.Type.MatchHint-import Data.ByteString---{- | picks 'M.Match' instance where 'Pattern' and 'Body' are of the same type--    'Hint' and inferrable 'Pattern' or 'Body' type determine the instance--    handy when working with 'OverloadedStrings', in other cases when compiler needs a hint--    >>> Test ("в"::ByteString) =~ "тихо в лесу"--    True--    >>> Once ("^all"::String) =~ "all the time"--    \["all"\]--    >>> PosLen' ("и"::String) =~ "бывает и хуже"--    \[(13,2)\]      -}-class (Hint hint, M.Match a a (F hint a)) =>-    MatchHint hint a where-    type F hint a-    match::hint (Pattern a) -> Body a -> F hint a-    match h0 = M.match $ unhint h0--    (=~)::hint a  -- ^ hint & pattern-            -> a          -- ^ body-            -> F hint a   -- ^ type defined by the instance, determined by the hint-    (=~) h0 = (M.=~) $ unhint h0---instance MatchHint Test String where-    type F Test String = Bool--instance MatchHint PosLen' String where-    type F PosLen' String = [PosLen]--instance MatchHint PosLen_ String where-    type F PosLen_ String = [[PosLen]]--instance MatchHint Once String where-    type F Once String = [String]--instance MatchHint All String where-    type F All String = [[String]]--instance MatchHint Test ByteString where-    type F Test ByteString = Bool--instance MatchHint PosLen' ByteString where-    type F PosLen' ByteString = [PosLen]--instance MatchHint PosLen_ ByteString where-    type F PosLen_ ByteString = [[PosLen]]--instance MatchHint Once ByteString where-    type F Once ByteString = [ByteString]--instance MatchHint All ByteString where-    type F All ByteString = [[ByteString]]
src/Text/Regex/Do/Pcre/Matchf.hs view
@@ -2,26 +2,38 @@ module Text.Regex.Do.Pcre.Matchf where  import Text.Regex.Do.Type.Do-import Text.Regex.Do.Type.Reexport-import qualified Text.Regex.Do.Pcre.Result as R-import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)-import Text.Regex.Do.Type.Regex_+import Text.Regex.Do.Type.Reexport as R+import Text.Regex.Do.Result as R+import Text.Regex.Base.RegexLike as R+import Text.Regex.Do.Type.MatchHint +type R_ b = R.RegexLike R.Regex b -class (Rx_ a b, Functor f) => Matchf f a b where-   marray_::Pattern a -> Body b -> f MatchArray-   poslen_::Pattern a -> Body b -> f [PosLen]-   poslen_ r0 b0 = R.poslen $ marray_ r0 b0 -instance Rx_ a b => Matchf Maybe a b where-   marray_ p0 (Body b0) = R.matchOnce (r_ p0) b0+class Matchf hint b where+    type H hint+    type P hint+    marray_::R_ b => hint (Pattern R.Regex) -> Body b -> H hint+    poslen_::R_ b => hint (Pattern R.Regex) -> Body b -> P hint -instance Rx_ a b => Matchf [] a b where-   marray_ p0 (Body b0) = R.matchAll (r_ p0) b0+instance Matchf Once b where+    type H Once = Maybe MatchArray+    type P Once = Maybe [PosLen]+    marray_ (Once (Pattern p0)) (Body b0) = R.matchOnce p0 b0+    poslen_ r0 b0 = R.poslen $ marray_ r0 b0 +instance Matchf All b where+    type H All = [MatchArray]+    type P All = [[PosLen]]+    marray_ (All (Pattern p0)) (Body b0) = R.matchAll p0 b0+    poslen_ r0 b0 = R.poslen $ marray_ r0 b0 -once::Rx_ a b => Pattern a -> Body b -> [b]      -- ^ matched content-once p0 b0 = maybe [] id $ R.allMatches b0 $ marray_ p0 b0 -all::Rx_ a b => Pattern a -> Body b -> [[b]]       -- ^ matched content-all p0 b0 = R.allMatches b0 $ marray_ p0 b0+once::(R_ b, R.Extract b) =>+    Pattern R.Regex -> Body b -> [b]      -- ^ matched content+once p0 b0 = maybe [] id $ R.allMatches b0 $ marray_ (Once p0) b0+++all::(R_ b, R.Extract b) =>+    Pattern R.Regex -> Body b -> [[b]]       -- ^ matched content+all p0 b0 = R.allMatches b0 $ marray_ (All p0) b0
− src/Text/Regex/Do/Pcre/Replace.hs
@@ -1,127 +0,0 @@-module Text.Regex.Do.Pcre.Replace-    (Replace(..))  where--import Text.Regex.Base.RegexLike as R-import Prelude as P-import Data.ByteString as B-import qualified Text.Regex.Do.Pcre.Option as O-import Text.Regex.Do.Type.Do-import Text.Regex.Do.Type.Reexport-import Text.Regex.Do.Pcre.Matchf-import qualified Text.Regex.Do.Pcre.ReplaceOpen as O-import Text.Regex.Do.Convert-import Text.Regex.Do.Type.Regex_-import Text.Regex.Do.Type.Extract-import Text.Regex.Do.Type.MatchHint----type Ro_ rx = (Regex_ rx, Opt_ rx)--rx'::Regex_ rx => Pattern rx -> [O.Comp] -> Pattern Regex-rx' p0 opt0 = Pattern $ ropt_ p0 opt0 []---{- | == dynamic group replace-   custom replacer fn returns replacement value. See 'O.defaultReplacer'--   >>> replacer::GroupReplacer String-       replacer = defaultReplacer 1 tweak1-             where tweak1 str1 = case str1 of-                                   "101" -> "[сто один]"-                                   "3" -> "[three]"-                                   otherwise -> trace str1 "?"--    'Once' vs 'All' options--    >>> replace (Once[]) (Pattern "\\w=(\\d{1,3})") replacer $ Body "a=101 b=3 12"--        "a=[сто один] b=3 12"--    >>> replace (All[]) (Pattern "\\w=(\\d{1,3})") replacer $ Body "a=101 b=3 12"--        "a=[сто один] b=[three] 12"---    == static replace for simple (no group) needle--    for no-regex 'ByteString' replacement see "Text.Regex.Do.Split"--    >>> replace (Once[Utf8]) (Pattern "менее") (Replacement  "более") $ Body "менее менее"--    "более менее"--    >>> replace (Once[]) (Pattern "^a\\s") (Replacement "A") $ Body "a bc хол.гор."--    "Abc хол.гор."      -}--class Replace hint rx r a where-    replace::hint [O.Comp] -> Pattern rx -> r a -> Body a -> a---instance Regex_ rx => Replace Once rx Replacement String where-    replace opt0@(Once opt1) p0 r0 b0 =-        let ma1 = marray_ p1 b1::Maybe MatchArray-            b1 = toByteString <$> b0-            r1 = toByteString <$> r0-            isUtf1 = O.Utf8 `P.elem` opt1-            bs1 = O.replace ma1 r1 b1-            p1 = rx' p0 opt1-        in if isUtf1 then toString bs1-            else vanilla_once p1 r0 b0---instance Regex_ rx => Replace All rx Replacement String where-    replace opt0@(All opt1) p0 r0 b0 =-        let ma2 = marray_ p0 b1::[MatchArray]-            b1 = toByteString <$> b0-            r1 = toByteString <$> r0-            isUtf1 = O.Utf8 `P.elem` opt1-            bs1 = O.replace ma2 r1 b1-            p1 = rx' p0 opt1-        in if isUtf1 then toString bs1-            else vanilla_all p1 r0 b0---instance Regex_ rx => Replace Once rx Replacement ByteString where-    replace opt0@(Once opt1) p0 = vanilla_once $ rx' p0 opt1--instance Regex_ rx => Replace All rx Replacement ByteString where-    replace opt0@(All opt1) p0 = vanilla_all $ rx' p0 opt1--instance Regex_ rx => Replace Once rx GroupReplacer ByteString where-    replace opt0@(Once opt1) p0 = vanilla_once $ rx' p0 opt1--instance Regex_ rx => Replace All rx GroupReplacer ByteString where-    replace opt0@(All opt1) p0 = vanilla_all $ rx' p0 opt1--instance Regex_ rx => Replace Once rx GroupReplacer String where-    replace opt0@(Once opt1) p0 = vanilla_once $ rx' p0 opt1--instance Regex_ rx => Replace All rx GroupReplacer String where-    replace opt0@(All opt1) p0 = vanilla_all $ rx' p0 opt1---type Vanilla_ f r a = (O.ReplaceOpen f r, Extract' a, RegexLike Regex a)-type Vanilla_once r a = Vanilla_ Maybe r a-type Vanilla_all r a = Vanilla_ [] r a---vanilla_once::Vanilla_once r a =>-        Pattern Regex ->-        r a ->-        Body a ->-            a-vanilla_once p0 r0 b0 =-   let ma1 = marray_ p0 b0::Maybe MatchArray-   in O.replace ma1 r0 b0---vanilla_all::Vanilla_all r a =>-        Pattern Regex ->-        r a ->-        Body a ->-            a-vanilla_all p0 r0 b0 =-   let ma2 = marray_ p0 b0:: [MatchArray]-   in O.replace ma2 r0 b0
− src/Text/Regex/Do/Pcre/ReplaceOpen.hs
@@ -1,144 +0,0 @@-{- | extensible and reusable replacement functions--    Run replacement with your preferred content types e.g. "Data.Text",-    from search results with non-PCRE regex or non-regex libs--    open an issue or a PR on <https://github.com/ciez/regex-do git> to request a new 'Extract'' instance--    "Data.Text" instance already works  -}--module Text.Regex.Do.Pcre.ReplaceOpen-    (ReplaceOpen(..),-    defaultReplacer,-    getGroup,-    replaceMatch-    )-    where--import Text.Regex.Base.RegexLike as R-import Data.Array as A-import Prelude as P-import Text.Regex.Do.Type.Do-import Text.Regex.Do.Pcre.Result as R-import Text.Regex.Do.Convert-import Text.Regex.Do.Type.Extract---{- | 'Replacement':--    >>> replace (Just [(4,3)::PosLen]) (Replacement "4567") (Body "abc 123 def"::Body Text)--    "abc 4567 def"---    'GroupReplacer' :--    >>> replacer::GroupReplacer Text-        replacer = defaultReplacer 1 tweak1        --  1: first match in group-              where tweak1 str1 = case str1 of-                                    "123" -> "[1-2-3]"-                                    otherwise -> traceShow str1 "?"--    >>> replace (Just ([(4,3),(8,2)]::[PosLen])) replacer (Body "abc 123 def"::Body Text)--        "abc [1-2-3] def"     -}--class ReplaceOpen f r where-   replace::(Extract' a, ToArray arr) =>-        f arr -> r a -> Body a -> a---instance ReplaceOpen Maybe Replacement where-   replace Nothing (Replacement repl0) (Body b0) = b0-   replace (Just ma0) (Replacement repl0) (Body b0) = firstGroup lpl1 (repl0, b0)-        where lpl1 = A.elems $ toArray ma0---instance ReplaceOpen [] Replacement where-   replace [] _ (Body b0) = b0-   replace ma0 (Replacement repl0) (Body b0) =-      let lpl1 = R.poslen $ toArray <$> ma0::[[PosLen]]-          foldFn1 lpl1 acc1 = firstGroup lpl1 (repl0,acc1)-      in P.foldr foldFn1 b0 lpl1---instance ReplaceOpen Maybe GroupReplacer where-   replace Nothing _ (Body b0) = b0-   replace (Just ma0) (GroupReplacer repl0) (Body b0) =-            let a1 = ReplaceAcc {-                                  acc = b0,-                                  pos_adj = 0-                                }-            in acc $ repl0 (toArray ma0) a1---instance ReplaceOpen [] GroupReplacer where-   replace [] _ (Body b0) = b0-   replace ma0 (GroupReplacer repl0) (Body b0) =-        let acc1 = ReplaceAcc { acc = b0, pos_adj = 0 }-        in acc $ P.foldl (flip repl0) acc1 $ toArray <$> ma0---firstGroup::Extract' a =>-    [PosLen] -> (a,a) -> a-firstGroup (pl0:_) r1@(new0,a0) = acc $ replaceMatch pl0 (new0, acc1)-    where acc1 = ReplaceAcc {-                    acc = a0,-                    pos_adj = 0-                    }------  dynamic-{- | Replaces specified (by idx) group match with tweaked value.-    Works for one common simple use case--    'GroupReplacer' can be used with complicated regex--    another custom dynamic replacer could e.g.-    inspect all group matches before looking up a replacement.     -}-defaultReplacer::Extract' a =>-        Int         -- ^ group idx-        -> (a -> a) -- ^ (group match -> replacement) tweak-            -> GroupReplacer a-defaultReplacer idx0 tweak0 = GroupReplacer fn1-    where fn1 (ma0::MatchArray) acc0 = maybe acc0 fn1 mval1-                where pl1 = ma0 A.! idx0 :: (R.MatchOffset, R.MatchLength)-                      mval1 = getGroup acc0 ma0 idx0-                      fn1 str1 = replaceMatch pl1 (str2, acc0)-                                 where str2 = tweak0 str1---{- | get group content safely--    see 'defaultReplacer' source for use example-    -}-getGroup::R.Extract a =>-    ReplaceAcc a -> MatchArray -> Int -> Maybe a-getGroup acc0 ma0 idx0 = if idx0 >= P.length ma0 then Nothing     --  safety catch-    else Just val1-    where pl1 = ma0 A.! idx0 :: (R.MatchOffset, R.MatchLength)-          pl2 = adjustPoslen pl1 acc0-          val1 = extract pl2 $ acc acc0---{- | call from your custom 'GroupReplacer' passed to 'replaceGroup'--     see 'defaultReplacer' source for use example     -}-replaceMatch::Extract' a =>-        PosLen      -- ^ replaceable, unadjusted-        -> (a, ReplaceAcc a)  -- ^ (new val, acc passed to 'GroupReplacer')-        -> ReplaceAcc a    -- ^ new acc-replaceMatch pl0@(_,l0) (new0, acc0) = ReplaceAcc {-                    acc = acc1,-                    pos_adj = pos_adj acc0 + l1 - l0-                    }-     where  pl1 = adjustPoslen pl0 acc0-            prefix1 = prefix pl1 $ acc acc0-            suffix1 = suffix pl1 $ acc acc0-            acc1 = concat' [prefix1, new0, suffix1]-            l1 = len' new0---adjustPoslen::PosLen -> ReplaceAcc a -> PosLen-adjustPoslen (p0,l0) acc0  = (p0 + pos_adj acc0, l0)
− src/Text/Regex/Do/Pcre/Result.hs
@@ -1,22 +0,0 @@-module Text.Regex.Do.Pcre.Result where--import qualified Data.Array as A(elems)-import Text.Regex.Base.RegexLike as R-import Text.Regex.Do.Type.Do---- | match offset, length-poslen::Functor f =>-    f MatchArray -> f [PosLen]-poslen = (A.elems <$>)----- | all groups-allMatches::(Functor f, R.Extract b) =>-    Body b -> f MatchArray -> f [b]-allMatches hay0 results0 = groupMatch hay0 <$> results0----- | matches for one group-groupMatch::R.Extract b =>-    Body b -> MatchArray -> [b]-groupMatch (Body b0) a0 = [R.extract tuple1 b0 |  tuple1 <- A.elems a0]
+ src/Text/Regex/Do/Pcre/Utf8/Match.hs view
@@ -0,0 +1,80 @@+{- | see "Text.Regex.Base.RegexLike" and "Text.Regex.Do.Pcre.Utf8.MatchHint"++    similar to "Text.Regex.Do.Pcre.Ascii.Match"++    'Pattern' & 'Body' are wrapped in 'Utf8_' encoding tag.+    This tag adds clarity, prevents calling Ascii functions by mistake.++    __'toByteString''__ converts String to 'Utf8_' 'ByteString'     -}+module Text.Regex.Do.Pcre.Utf8.Match+    (Match(..),+    (=~),+    R.extract   -- | 'extract' is reexport from "Text.Regex.Base.RegexLike"+    ) where++import Text.Regex.Do.Type.Reexport as R+import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex)+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Pcre.Matchf as F+import Text.Regex.PCRE.Wrap()+import Text.Regex.Do.Type.Regex as T+import Text.Regex.Do.Type.MatchHint+import Text.Regex.Do.Pcre.Option+import Text.Regex.Do.Convert+import Data.ByteString++++class Match enc a b out where+    match::Pattern (enc a) -> Body (enc b) -> out++(=~)::Match Utf8_ a b out =>+    a     -- ^ pattern+    -> b    -- ^ body+    -> out+(=~) p0 b0 = match (Pattern $ Utf8_ p0) (Body $ Utf8_ b0)+++-- | match once+instance Rx_ a b => Match Utf8_ a b [b] where+    match p0 b0 = once (mr_ p0) $ val <$> b0++{- ^ >>> let rx1 = makeRegexOpt' (Pattern $ toByteString' "左") [] []      --  add options as needed+         rx2 = Utf8_ <$> rx1+         m1 = U.match rx2 (Body $ toByteString' "100メートル左折後、左")::[ByteString]+      m1 `shouldBe` [toByteString "左"]        -}+++instance Rx_ a b => Match Utf8_ a b Bool where+    match p0 (Body b0) = R.matchTest (makeRegexOpt p0 [Utf8] []) $ val b0+{- ^ test. Note that a and b may be different types e.g. 'ByteString' and 'String'++    >>>  toByteString "в" =~ ("тихо в лесу"::String)::Bool++    True        -}++-- | match all+instance Rx_ a b => Match Utf8_ a b [[b]] where+    match p0 b0 = F.all (mr_ p0) $ val <$> b0+{- ^  >>> ("well"::String) =~ ("all is well that ends well"::String)::[[String]]++     \[["well"\],\["well"\]]        -}++-- | match once+instance Rx_ a b => Match Utf8_ a b [PosLen] where+    match p0 b0 = maybe [] id $ poslen_ (Once $ mr_ p0) $ val <$> b0+{- ^ >>> ("и"::String) =~ ("бывает и хуже"::String)::[PosLen]++     \[(13,2)\]     -}++-- | match all+instance Rx_ a b => Match Utf8_ a b [[PosLen]] where+    match p0 b0 = poslen_ (All $ mr_ p0) $ val <$> b0+++mr_::T.Regex a => Pattern a -> Pattern R.Regex+mr_ p0 = makeRegexOpt' p0 [Utf8] []+++dum_::String -> Utf8_ ByteString+dum_ = toByteString'
+ src/Text/Regex/Do/Pcre/Utf8/MatchHint.hs view
@@ -0,0 +1,75 @@+-- | see "Text.Regex.Do.Pcre.Ascii.MatchHint" about MatchHint vs Match+++module Text.Regex.Do.Pcre.Utf8.MatchHint+    (MatchHint(..),+    (=~)) where++import Text.Regex.Do.Type.Do hiding (Once,All)+import Text.Regex.PCRE.Wrap()+import qualified Text.Regex.Do.Pcre.Utf8.Match as M+import Text.Regex.Do.Type.MatchHint+import Data.ByteString+++{- | picks 'M.Match' instance where 'Pattern' and 'Body' are of the same type++    'Hint' and inferrable 'Pattern' or 'Body' type determine the instance++    handy when working with 'OverloadedStrings', in other cases when compiler needs a hint  -}+class (Hint hint, M.Match enc a a (F hint a)) =>+    MatchHint hint enc a where+    type F hint a+    match::hint (Pattern (enc a)) -> Body (enc a) -> F hint a+    match h0 = M.match $ unhint h0+++(=~)::MatchHint hint Utf8_ a =>+    hint a              -- ^ hint pattern+        -> a            -- ^ body+        -> F hint a     -- ^ type defined by the instance, determined by the hint+(=~) h0 = (M.=~) $ unhint h0+++instance MatchHint Test Utf8_ String where+    type F Test String = Bool+++instance MatchHint PosLen' Utf8_ String where+    type F PosLen' String = [PosLen]++{- ^ >>> PosLen' ("и"::String) =~ "бывает и хуже"++    \[(13,2)\]      -}++instance MatchHint PosLen_ Utf8_ String where+    type F PosLen_ String = [[PosLen]]++instance MatchHint Once Utf8_ String where+    type F Once String = [String]++{- ^ >>> Once ("^all"::String) =~ "all the time"++    \["all"\]       -}++instance MatchHint All Utf8_ String where+    type F All String = [[String]]++instance MatchHint Test Utf8_ ByteString where+    type F Test ByteString = Bool++{- ^ >>> Test (toByteString "в") =~ toByteString "тихо в лесу"++    True    -}++instance MatchHint PosLen' Utf8_ ByteString where+    type F PosLen' ByteString = [PosLen]++instance MatchHint PosLen_ Utf8_ ByteString where+    type F PosLen_ ByteString = [[PosLen]]++instance MatchHint Once Utf8_ ByteString where+    type F Once ByteString = [ByteString]++instance MatchHint All Utf8_ ByteString where+    type F All ByteString = [[ByteString]]
+ src/Text/Regex/Do/Pcre/Utf8/Replace.hs view
@@ -0,0 +1,83 @@+{- | see also "Text.Regex.Do.Pcre.Ascii.Replace"++    'Pattern' & 'Body' are wrapped in 'Utf8_' encoding tag.+    This tag adds clarity, prevents calling Ascii functions by mistake.++    __'toByteString''__ converts String to 'Utf8_' 'ByteString'     -}++module Text.Regex.Do.Pcre.Utf8.Replace+    (Replace(..))  where++import Prelude as P+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Pcre.Matchf+import qualified Text.Regex.Do.ReplaceOpen as O+import Text.Regex.Do.Type.Regex as T+import Text.Regex.Do.Type.MatchHint+import Text.Regex.Do.Convert+import Data.ByteString+++class Replace all enc a repl where+    replace::all (Pattern (enc a)) -> repl (enc a) -> Body (enc a) -> a+++instance Replace Once Utf8_ String Replacement where+    replace = replace_str marray_++instance Replace All Utf8_ String Replacement where+    replace = replace_str marray_++replace_str f0 p0 r0 b0 =+   let ma1 = f0 p1 b1+       b1 = toByteString . val <$> b0+       r1 = toByteString <$> (val <$> r0)+       p1 = T.makeRegex' . (toByteString' . val <$>) <$> p0+   in toString $ O.replace ma1 r1 b1+++instance Replace Once Utf8_ ByteString Replacement where+    replace = replace_bs marray_++instance Replace All Utf8_ ByteString Replacement where+    replace = replace_bs marray_++replace_bs f0 p0 r0 b0 =+   let ma1 = f0 p1 b1+       b1 = val <$> b0+       p1 = T.makeRegex' . (Utf8_ . val <$>) <$> p0+   in O.replace ma1 (val <$> r0) b1++++instance Replace Once Utf8_ ByteString GroupReplacer where+    replace = replace_bs' marray_++instance Replace All Utf8_ ByteString GroupReplacer where+    replace = replace_bs' marray_++{- ^ >>> replacer::GroupReplacer (Utf8_ ByteString)+         replacer = defaultReplacer 1 tweak1+          where tweak1 bs1 = toByteString' $+                                if bs1 == toByteString' "左" then+                                      "ー右ー"+                                       else "?"+++     >>> runFn1 `shouldBe` toByteString "100メートルー右ー折後、左"+            where runFn1 =+                     let rx1 = Pattern $ toByteString' "(?<=ル)(左)"+                         body1 = Body $ toByteString' "100メートル左折後、左"+                     in replace (All rx1) replacer body1        -}+++replace_bs' f0 p0 r0 b0 =+   let ma1 = f0 p1 b1+       b1 = val <$> b0+       p1 = T.makeRegex' . (Utf8_ . val <$>) <$> p0+   in O.replace ma1 (val' r0) b1+++{- ^ to tweak regex with 'Comp' or 'Exec', see "Text.Regex.Do.Type.Regex"++    note 'Once_Utf8' and 'All_Utf8' hints   -}
+ src/Text/Regex/Do/ReplaceOpen.hs view
@@ -0,0 +1,143 @@+{- | extensible and reusable replacement functions++    Run replacement with your preferred content types e.g. "Data.Text",+    from search results with non-PCRE regex or non-regex libs++    open an issue or a PR on <https://github.com/ciez/regex-do git> to request a new 'Extract'' instance++    "Data.Text" instance already works  -}++module Text.Regex.Do.ReplaceOpen+    (ReplaceOpen(..),+    defaultReplacer,+    getGroup,+    replaceMatch+    )+    where++import Text.Regex.Base.RegexLike as R+import Data.Array as A+import Prelude as P+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Result as R+import Text.Regex.Do.Convert+import Text.Regex.Do.Type.Extract+++{- | 'Replacement':++    >>> replace (Just [(4,3)::PosLen]) (Replacement "4567") (Body "abc 123 def"::Body Text)++    "abc 4567 def"+++    'GroupReplacer' :++    >>> replacer::GroupReplacer Text+        replacer = defaultReplacer 1 tweak1        --  1: first match in group+              where tweak1 str1 = case str1 of+                                    "123" -> "[1-2-3]"+                                    otherwise -> traceShow str1 "?"++    >>> replace (Just ([(4,3),(8,2)]::[PosLen])) replacer (Body "abc 123 def"::Body Text)++        "abc [1-2-3] def"     -}++class ReplaceOpen f r where+   replace::(Extract' a, ToArray arr) =>+        f arr -> r a -> Body a -> a+++instance ReplaceOpen Maybe Replacement where+   replace Nothing (Replacement repl0) (Body b0) = b0+   replace (Just ma0) (Replacement repl0) (Body b0) = firstGroup lpl1 (repl0, b0)+        where lpl1 = A.elems $ toArray ma0+++instance ReplaceOpen [] Replacement where+   replace [] _ (Body b0) = b0+   replace ma0 (Replacement repl0) (Body b0) =+      let lpl1 = R.poslen $ toArray <$> ma0::[[PosLen]]+          foldFn1 lpl1 acc1 = firstGroup lpl1 (repl0,acc1)+      in P.foldr foldFn1 b0 lpl1+++instance ReplaceOpen Maybe GroupReplacer where+   replace Nothing _ (Body b0) = b0+   replace (Just ma0) (GroupReplacer repl0) (Body b0) =+            let a1 = ReplaceAcc {+                                  acc = b0,+                                  pos_adj = 0+                                }+            in acc $ repl0 (toArray ma0) a1+++instance ReplaceOpen [] GroupReplacer where+   replace [] _ (Body b0) = b0+   replace ma0 (GroupReplacer repl0) (Body b0) =+        let acc1 = ReplaceAcc { acc = b0, pos_adj = 0 }+        in acc $ P.foldl (flip repl0) acc1 $ toArray <$> ma0+++firstGroup::Extract' a =>+    [PosLen] -> (a,a) -> a+firstGroup (pl0:_) r1@(new0,a0) = acc $ replaceMatch pl0 (new0, acc1)+    where acc1 = ReplaceAcc {+                    acc = a0,+                    pos_adj = 0+                    }+++--  dynamic+{- | Replaces specified (by idx) group match with tweaked value.+    Works for one common simple use case++    'GroupReplacer' can be used with complicated regex++    another custom dynamic replacer could e.g.+    inspect all group matches before looking up a replacement.     -}+defaultReplacer::Extract' a =>+        Int         -- ^ group idx+        -> (a -> a) -- ^ (group match -> replacement) tweak+            -> GroupReplacer a+defaultReplacer idx0 tweak0 = GroupReplacer fn1+    where fn1 (ma0::MatchArray) acc0 = maybe acc0 fn1 mval1+                where pl1 = ma0 A.! idx0 :: (R.MatchOffset, R.MatchLength)+                      mval1 = getGroup acc0 ma0 idx0+                      fn1 str1 = replaceMatch pl1 (str2, acc0)+                                 where str2 = tweak0 str1+++{- | get group content safely++    see 'defaultReplacer' source for use example+    -}+getGroup::R.Extract a =>+    ReplaceAcc a -> MatchArray -> Int -> Maybe a+getGroup acc0 ma0 idx0 = if idx0 >= P.length ma0 then Nothing     --  safety catch+    else Just val1+    where pl1 = ma0 A.! idx0 :: (R.MatchOffset, R.MatchLength)+          pl2 = adjustPoslen pl1 acc0+          val1 = extract pl2 $ acc acc0+++{- | call from your custom 'GroupReplacer' passed to 'replaceGroup'++     see 'defaultReplacer' source for use example     -}+replaceMatch::Extract' a =>+        PosLen      -- ^ replaceable, unadjusted+        -> (a, ReplaceAcc a)  -- ^ (new val, acc passed to 'GroupReplacer')+        -> ReplaceAcc a    -- ^ new acc+replaceMatch pl0@(_,l0) (new0, acc0) = ReplaceAcc {+                    acc = acc1,+                    pos_adj = pos_adj acc0 + l1 - l0+                    }+     where  pl1 = adjustPoslen pl0 acc0+            prefix1 = prefix pl1 $ acc acc0+            suffix1 = suffix pl1 $ acc acc0+            acc1 = concat' [prefix1, new0, suffix1]+            l1 = len' new0+++adjustPoslen::PosLen -> ReplaceAcc a -> PosLen+adjustPoslen (p0,l0) acc0  = (p0 + pos_adj acc0, l0)
+ src/Text/Regex/Do/Result.hs view
@@ -0,0 +1,22 @@+module Text.Regex.Do.Result where++import qualified Data.Array as A(elems)+import Text.Regex.Base.RegexLike as R+import Text.Regex.Do.Type.Do++-- | match offset, length+poslen::Functor f =>+    f MatchArray -> f [PosLen]+poslen = (A.elems <$>)+++-- | all groups+allMatches::(Functor f, R.Extract b) =>+    Body b -> f MatchArray -> f [b]+allMatches hay0 results0 = groupMatch hay0 <$> results0+++-- | matches for one group+groupMatch::R.Extract b =>+    Body b -> MatchArray -> [b]+groupMatch (Body b0) a0 = [R.extract tuple1 b0 |  tuple1 <- A.elems a0]
src/Text/Regex/Do/Trim.hs view
@@ -4,8 +4,10 @@ import Data.Char(isSpace) import qualified Data.ByteString as B import Text.Regex.Do.Convert-import Text.Regex.Do.Pcre.Replace+import Text.Regex.Do.Pcre.Ascii.Replace import Text.Regex.Do.Type.MatchHint+import Text.Regex.Do.Type.Regex+import Text.Regex.Do.Pcre.Option   {- | removes leading and trailing spaces and tabs   -}@@ -15,10 +17,12 @@   instance Trim B.ByteString where-    trim bs1 = replace (All []) rx1 repl1 $ Body bs1+    trim bs1 = replace (All rx2) repl1 $ Body bs1        where repl1 = Replacement B.empty-             rx1 = rxFn "(^[\\s\\t]+)|([\\s\\t]+$)"-             rxFn = Pattern . toByteString+             rx1 = "(^[\\s\\t]+)|([\\s\\t]+$)"+             rx2 = let p1 = Pattern $ toByteString rx1+                        in makeRegexOpt' p1 [Blank] []+  instance  Trim String where     trim = f . f
src/Text/Regex/Do/Type/Do.hs view
@@ -6,20 +6,66 @@ -- | see "Text.Regex.Do.Pcre.ReplaceOpen" 'defaultReplacer' for example implementation newtype GroupReplacer b = GroupReplacer (MatchArray -> ReplaceAcc b -> ReplaceAcc b) -- MatchArray -> acc -> acc - data ReplaceAcc b = ReplaceAcc {     acc::b,   -- ^ content with some replacements made     pos_adj::Int    {- ^ position adjustment: group replacement length may differ from replaced text length -}     } +instance Functor ReplaceAcc where+    fmap fn0 r0 = r0 { acc = fn0 $ acc r0 } ++ -- | Needle data Pattern a = Pattern a  deriving (Functor)          -- Bs, String, RegexPcre+instance Applicative Pattern where+    pure p0 = Pattern p0+    (<*>) (Pattern f0) (Pattern a0) = Pattern $ f0 a0 + -- | Haystack data Body b = Body b deriving (Functor)                -- Bs, String+instance Applicative Body where+    pure p0 = Body p0+    (<*>) (Body f0) (Body a0) = Body $ f0 a0 + data Replacement r = Replacement r deriving (Functor)     --    Bs, String+instance Applicative Replacement where+    pure p0 = Replacement p0+    (<*>) (Replacement f0) (Replacement a0) = Replacement $ f0 a0  -- | Offset, Length type PosLen = (MatchOffset, MatchLength)++++newtype Utf8_ a = Utf8_ a       -- ^ values+        deriving (Functor,Eq,Ord)++instance Applicative Utf8_ where+    pure p0 = Utf8_ p0+    (<*>) (Utf8_ f0) (Utf8_ a0) = Utf8_ $ f0 a0+++-- ^ does not do any codec. Plain wrap / unwrap newtype+class Enc enc where+    val::enc a -> a+    enc::a -> enc a++-- ^ does not do any codec. Plain wrap / unwrap newtype+class Enc' f enc where+    val'::f (enc a) -> f a+    enc'::f a -> f (enc a)+++instance Enc Utf8_ where+    val (Utf8_ v0) = v0+    enc = Utf8_+++instance Enc enc => Enc' GroupReplacer enc where+    val' (GroupReplacer fn0) = GroupReplacer $+        \ma1 acc1 -> val <$> (fn0 ma1 $ enc <$> acc1)+    enc' (GroupReplacer fn0) = GroupReplacer $+        \ma1 acc1 -> enc <$> (fn0 ma1 $ val <$> acc1)
src/Text/Regex/Do/Type/Extract.hs view
@@ -1,9 +1,11 @@ module Text.Regex.Do.Type.Extract where -import Text.Regex.Base.RegexLike as R+import Text.Regex.Base.RegexLike as R hiding (empty)+import qualified Text.Regex.Base.RegexLike as R (empty) import Prelude as P import Data.ByteString as B-import Data.Text as T+import Data.Text as T hiding (empty)+import qualified Data.Text as T (empty) import Text.Regex.Do.Type.Do  @@ -23,6 +25,17 @@ instance Extract' B.ByteString where    concat' = B.concat    len' = B.length+++instance Extract (Utf8_ B.ByteString) where+    before i0 = (before i0 <$>)+    after i0 = (after i0 <$>)+    empty = Utf8_ R.empty+++instance Extract' (Utf8_ B.ByteString) where+   concat' = Utf8_ . B.concat . (val <$>)+   len' = B.length . val   instance Extract Text where
src/Text/Regex/Do/Type/MatchHint.hs view
@@ -2,17 +2,46 @@  newtype Test a = Test a     -- ^ test: does body match pattern? newtype Once a = Once a     -- ^ values-newtype All a = All a       -- ^ values+        deriving (Functor)++newtype All a = All a        -- ^ values+        deriving (Functor)+ newtype PosLen' a = PosLen' a   -- ^ once newtype PosLen_ a = PosLen_ a   -- ^ all   class Hint hint where     unhint::hint a -> a+    hint::a -> hint a  -instance Hint Test where unhint (Test a0) = a0-instance Hint Once where unhint (Once a0) = a0-instance Hint All where unhint (All a0) = a0-instance Hint PosLen' where unhint (PosLen' a0) = a0-instance Hint PosLen_ where unhint (PosLen_ a0) = a0+instance Hint Test where+    unhint (Test a0) = a0+    hint = Test++instance Hint Once where+    unhint (Once a0) = a0+    hint = Once++instance Hint All where+    unhint (All a0) = a0+    hint = All++instance Hint PosLen' where+    unhint (PosLen' a0) = a0+    hint = PosLen'++instance Hint PosLen_ where+    unhint (PosLen_ a0) = a0+    hint = PosLen_+++instance Applicative Once where+    pure p0 = Once p0+    (<*>) (Once f0) (Once a0) = Once $ f0 a0+++instance Applicative All where+    pure p0 = All p0+    (<*>) (All f0) (All a0) = All $ f0 a0
+ src/Text/Regex/Do/Type/Regex.hs view
@@ -0,0 +1,60 @@+module Text.Regex.Do.Type.Regex+    (Regex(..),+    makeRegex',+    makeRegexOpt',+    Rx_, Opt_, Ro_) where++import qualified Text.Regex.Base.RegexLike as R+import qualified Text.Regex.Do.Type.Reexport as R+import Data.ByteString+import Text.Regex.Do.Type.Do+import Text.Regex.Do.Pcre.Option+++class Regex a where+   makeRegex::Pattern a -> R.Regex+   makeRegexOpt::Pattern a -> [Comp] -> [Exec] -> R.Regex+++makeRegex'::Regex a => Pattern a -> Pattern R.Regex+makeRegex' = Pattern . makeRegex++makeRegexOpt'::Regex a => Pattern a -> [Comp] -> [Exec] -> Pattern R.Regex+makeRegexOpt' p0 c0 e0 = Pattern $ makeRegexOpt p0 c0 e0++++instance Regex a => Regex (Utf8_ a) where+   makeRegex p0 = makeRegexOpt (Pattern val <*> p0) [Utf8] []+   makeRegexOpt p0 c0 e0 = makeRegexOpt (Pattern val <*> p0) (Utf8:c0) e0+++instance Regex ByteString where+   makeRegex (Pattern p0) = R.makeRegex p0+   makeRegexOpt = makeRegexOpts+++instance Regex String where+   makeRegex (Pattern p0) = R.makeRegex p0+   makeRegexOpt = makeRegexOpts+++instance Regex R.Regex where+   makeRegex (Pattern p0) = p0+   makeRegexOpt (Pattern p0) _ _ = p0+++-- | tweak Regex with options+makeRegexOpts::Opt_ a =>+    Pattern a ->+        [Comp] -> [Exec] ->+            R.Regex+makeRegexOpts (Pattern pat0) comp0 exec0 = rx1+   where c1 = comp comp0+         e1 = exec exec0+         rx1 = R.makeRegexOpts c1 e1 pat0+++type Rx_ a b = (Regex a, R.Extract b, R.RegexLike R.Regex b)+type Opt_ a = R.RegexMaker R.Regex R.CompOption R.ExecOption a+type Ro_ rx = (Regex rx, Opt_ rx)
− src/Text/Regex/Do/Type/Regex_.hs
@@ -1,40 +0,0 @@-module Text.Regex.Do.Type.Regex_ where--import qualified Text.Regex.Base.RegexLike as R-import Text.Regex.Do.Type.Reexport-import Data.ByteString-import Text.Regex.Do.Type.Do-import Text.Regex.Do.Pcre.Option---class Regex_ a where-   r_::Pattern a -> Regex-   ropt_::Pattern a -> [Comp] -> [Exec] -> Regex---instance Regex_ ByteString where-   r_ (Pattern p0) = R.makeRegex p0-   ropt_ = makeRegexOpts--instance Regex_ String where-   r_ (Pattern p0) = R.makeRegex p0-   ropt_ = makeRegexOpts--instance Regex_ Regex where-   r_ (Pattern p0) = p0-   ropt_ (Pattern p0) _ _ = p0---type Rx_ a b = (Regex_ a, R.Extract b, R.RegexLike Regex b)-type Opt_ a = R.RegexMaker Regex CompOption ExecOption a----- | tweak Regex with options-makeRegexOpts::Opt_ a =>-    Pattern a ->-        [Comp] -> [Exec] ->-            Regex-makeRegexOpts (Pattern pat0) comp0 exec0 = rx1-   where c1 = comp comp0-         e1 = exec exec0-         rx1 = R.makeRegexOpts c1 e1 pat0
test/Main.hs view
@@ -3,17 +3,18 @@ import qualified TestRegex.TestFormat as F import qualified TestRegex.TestPcre as P import qualified TestRegex.TestReplace as R+import qualified TestRegex.TestReplaceUtf as U import qualified TestRegex.TestReplaceOpen as O import qualified TestRegex.TestSplit as S import qualified TestRegex.TestTrim as T  - main::IO() main = do             F.main             P.main-            R.main             S.main             T.main             O.main+            R.main+            U.main
test/TestRegex/TestPcre.hs view
@@ -2,11 +2,14 @@  import Test.Hspec import Text.Regex.Do.Type.Do as M-import Text.Regex.Do.Pcre.Match as M+import Text.Regex.Do.Pcre.Ascii.Match as M+import Text.Regex.Do.Pcre.Utf8.Match as U+import Text.Regex.Do.Pcre.Ascii.MatchHint as S+import Text.Regex.Do.Pcre.Utf8.MatchHint as Su import Text.Regex.Do.Convert import Data.ByteString-import Text.Regex.Do.Pcre.MatchHint as S import Text.Regex.Do.Type.MatchHint as S+import Text.Regex.Do.Type.Regex   main::IO()@@ -20,10 +23,23 @@      it " cd " $ S.match (PosLen' $ Pattern ("^cd"::String)) (Body "abcde") `shouldBe` []      it " ab " $ S.match (Test $ Pattern ("^ab"::String)) (Body "abc") `shouldBe` True      it "doc 1" $ Test ("в"::ByteString) S.=~ "тихо в лесу" `shouldBe` True+     it "doc 1" $ Test (toByteString "в") Su.=~ toByteString "тихо в лесу" `shouldBe` True      it "doc 2" $ S.Once ("^all"::String) S.=~ "all the time" `shouldBe` ["all"]      it "doc 3" $ S.Once ("^all"::ByteString) S.=~ "all the time" `shouldBe` ["all"]      it "doc 4" $ S.All ("well"::ByteString) S.=~ "all is well that ends well" `shouldBe` ([["well"],["well"]])      it "doc 5" $ PosLen' ("и"::String) S.=~ "бывает и хуже" `shouldBe` [(13,2)]+     it "doc 6" $ PosLen' ("à"::String) S.=~ "tourner à gauche" `shouldBe` [(8,2)]+     it "doc 7" $ do+        let rx1 = makeRegexOpt' (Pattern $ toByteString'"左") [] []+            rx2 = Utf8_ <$> rx1+            m1 = U.match rx2 (Body $ toByteString' "100メートル左折後、左")::[ByteString]+        m1 `shouldBe` [toByteString "左"]+     it "doc 8" $ do+        let t1 = toByteString "в" U.=~ ("тихо в лесу"::String)::Bool+        t1 `shouldBe` True+     it "doc 9" $ do+        let m1 = ("well"::String) U.=~ ("all is well that ends well"::String)::[[String]]+        m1 `shouldBe` ([["well"],["well"]]::[[String]])  n = "d1" h = Body "abcd1efg d1hij"
test/TestRegex/TestReplace.hs view
@@ -4,13 +4,14 @@ import Test.Hspec import Text.Regex.Do.Type.Do -import Text.Regex.Do.Pcre.Replace as R-import Text.Regex.Do.Pcre.ReplaceOpen hiding (replace)+import Text.Regex.Do.Pcre.Ascii.Replace as R+import qualified Text.Regex.Do.Pcre.Utf8.Replace as U+import Text.Regex.Do.ReplaceOpen hiding (replace) import Text.Regex.Do.Convert import Data.ByteString as B import Debug.Trace import Text.Regex.Do.Type.MatchHint-import Text.Regex.Do.Pcre.Option+--import Text.Regex.Do.Pcre.Option  main::IO() main = do@@ -24,19 +25,19 @@ doc = hspec $ do        describe "Pcre.Replace doc" $ do           it "replaceGroup 1" $ do-            replace (Once []) (Pattern "\\w=(\\d{1,3})") replacer (Body "a=101 b=3 12")+            replace (Once (Pattern "\\w=(\\d{1,3})")) replacer (Body "a=101 b=3 12")                 `shouldBe` "a=[сто один] b=3 12"           it "replaceGroup 2" $ do-            replace (All []) (Pattern "\\w=(\\d{1,3})") replacer (Body "a=101 b=3 12")+            replace (All (Pattern "\\w=(\\d{1,3})")) replacer (Body "a=101 b=3 12")                 `shouldBe` "a=[сто один] b=[three] 12"           it "replace 3" $ do-            replace (Once [Utf8]) (Pattern "менее") (Replacement  "более") (Body "менее менее")+            U.replace (Once (Pattern $ Utf8_ "менее")) (Replacement $ Utf8_ $ "более") (Body $ Utf8_ "менее менее")                 `shouldBe` "более менее"           it "replace 4" $ do-            replace (All[Utf8]) (Pattern "менее") (Replacement  "боле") (Body "менее менее")+            U.replace (All (Pattern $ Utf8_ "менее")) (Replacement $ Utf8_ $ "боле") (Body $ Utf8_ "менее менее")                 `shouldBe` "боле боле"           it "replace 5" $ do-            replace (Once[]) (Pattern "^a\\s") (Replacement "A") (Body "a bc хол.гор.")+            replace (Once (Pattern "^a\\s")) (Replacement "A") (Body "a bc хол.гор.")                 `shouldBe` "Abc хол.гор."  @@ -44,9 +45,9 @@ onceUtf8 = hspec $ do        describe "Pcre.Replace Once Utf8" $ do           it "^a\\s" $ do-            replace (Once[]) (Pattern "^a\\s") (Replacement "A") (Body "a bc хол.гор.") `shouldBe` "Abc хол.гор."+            replace (Once (Pattern "^a\\s")) (Replacement "A") (Body "a bc хол.гор.") `shouldBe` "Abc хол.гор."           it "^b\\s" $ do-            replace (Once[]) (Pattern "^b\\s") (Replacement "A") (Body "a bc хол.гор.") `shouldBe` "a bc хол.гор."+            replace (Once (Pattern "^b\\s")) (Replacement "A") (Body "a bc хол.гор.") `shouldBe` "a bc хол.гор."   latinOnceAll::IO()@@ -61,7 +62,7 @@                            body1 = Body $ toByteString haystack1                            haystack1 = "a=10 b=11 12"                            repl1  = replacement "text1"-                     in replace (hint1 []) rx1 repl1 body1+                     in replace (hint1 rx1) repl1 body1   pattern::String -> Pattern ByteString@@ -76,13 +77,13 @@ groupReplace =  hspec $ do          describe "Pcre.Replace group" $ do             it "Once" $ do-               runFn1 (Once[Utf8]) `shouldBe` "a=[сто один] b=3 12"+               runFn1 Once `shouldBe` "a=[сто один] b=3 12"             it "All" $ do-               runFn1 (All[Utf8]) `shouldBe` "a=[сто один] b=[three] 12"+               runFn1 All `shouldBe` "a=[сто один] b=[three] 12"             where runFn1 opts1 =                      let   rx1 = Pattern "\\w=(\\d{1,3})"                            body1 = Body "a=101 b=3 12"-                     in replace opts1 rx1 replacer body1+                     in replace (opts1 rx1) replacer body1   replacer::GroupReplacer String
test/TestRegex/TestReplaceOpen.hs view
@@ -2,7 +2,7 @@ module TestRegex.TestReplaceOpen where  import Test.Hspec-import Text.Regex.Do.Pcre.ReplaceOpen as O+import Text.Regex.Do.ReplaceOpen as O import Text.Regex.Do.Type.Do import Data.Text import Text.Regex.Do.Convert()
+ test/TestRegex/TestReplaceUtf.hs view
@@ -0,0 +1,31 @@+module TestRegex.TestReplaceUtf where++import Test.Hspec+import Text.Regex.Do.Type.Do+import Data.ByteString+import Text.Regex.Do.Convert+import Text.Regex.Do.Pcre.Utf8.Replace as U+import Text.Regex.Do.Type.MatchHint+import Text.Regex.Do.ReplaceOpen+++main::IO()+main = groupReplace++groupReplace::IO()+groupReplace =  hspec $ do+       describe "TestRegex.TestReplaceUtf" $ do+            it "All" $ do+               runFn1 `shouldBe` toByteString "100メートルー右ー折後、左"+            where runFn1 =+                     let rx1 = Pattern $ toByteString' "(?<=ル)(左)"+                         body1 = Body $ toByteString' "100メートル左折後、左"+                     in U.replace (All rx1) replacer body1+++replacer::GroupReplacer (Utf8_ ByteString)+replacer = defaultReplacer 1 tweak1+      where tweak1 bs1 = toByteString' $+                            if bs1 == toByteString' "左" then+                                  "ー右ー"+                                  else "?"
test/TestRegex/TestSplit.hs view
@@ -36,19 +36,19 @@         describe "StringSearch.Search zerolength" $ do           it "break" $ do-            evaluate (errFn $ break Drop) `shouldThrow` anyException+            evaluate (errFn1 $ break Drop) `shouldThrow` anyException           it "break front" $ do-            evaluate (errFn $ break Front) `shouldThrow` anyException+            evaluate (errFn1 $ break Front) `shouldThrow` anyException           it "break end" $ do-            evaluate (errFn $ break End) `shouldThrow` anyException+            evaluate (errFn1 $ break End) `shouldThrow` anyException           it "replace" $ do             evaluate (S.replace (Pattern B.empty) with body) `shouldThrow` anyException           it "split" $ do-            evaluate (errFn $ split Drop) `shouldThrow` anyException+            evaluate (errFn2 $ split Drop) `shouldThrow` anyException           it "split end" $ do-            evaluate (errFn $ split End) `shouldThrow` anyException+            evaluate (errFn2 $ split End) `shouldThrow` anyException           it "split front" $ do-            evaluate (errFn $ split Front) `shouldThrow` anyException+            evaluate (errFn2 $ split Front) `shouldThrow` anyException         describe "StringSearch.Search break delim not found" $ do             it "delim not found" $ do@@ -67,7 +67,8 @@                split_sp1 = split Drop pat_sp body_sp                splitFront1 = split Front pat body                splitEnd1 = split End pat body-               errFn fn1 = fn1 (Pattern B.empty) body+               errFn1 fn1 = fn1 (Pattern B.empty) body+               errFn2 fn1 = fn1 (Pattern B.empty) body                b = toByteString                --   break delim not found                pat_nf = Pattern ":"