diff --git a/regex-do.cabal b/regex-do.cabal
--- a/regex-do.cabal
+++ b/regex-do.cabal
@@ -1,5 +1,5 @@
 name:                regex-do
-version:             1.0
+version:             1.1
 synopsis:            PCRE regex funs
 description:         Convenience functions to search, replace, format String | ByteString with PCRE regex
 author:              Imants Cekusins
@@ -24,14 +24,16 @@
           Regexdo.TypeRegex
           Regexdo.Convert
 
+  other-modules:
+
   ghc-options:  -fwarn-unused-imports
     
-  build-depends:  base >=4.8 && <4.9,
-              regex-base >= 0.93.2,
-              regex-pcre >= 0.94.4,
-              stringsearch >= 0.3.6.6,
-              bytestring >= 0.10.6.0,
-              array >= 0.5.1.0,
+  build-depends:  base <= 5.0,
+              regex-base,
+              regex-pcre,
+              stringsearch,
+              bytestring,
+              array,
               text
 
 
@@ -44,6 +46,8 @@
                         OverloadedStrings
                         FlexibleContexts
                         ConstraintKinds
+                        ScopedTypeVariables
+                        DeriveFunctor
                        
 
 test-suite spec
@@ -58,6 +62,8 @@
                         OverloadedStrings
                         FlexibleContexts
                         ConstraintKinds
+                        ScopedTypeVariables
+                        DeriveFunctor
 
 
   main-is: Main.hs
@@ -68,13 +74,13 @@
         TestRegex.StringSearch
         TestRegex.TestTrim
 
-  build-depends:  base >= 4.8,
-                  hspec >= 2.1.7,
-                  QuickCheck >= 2.8.1,
-                  regex-base >= 0.93.2,
-                  regex-pcre >= 0.94.4,
-                  stringsearch >= 0.3.6.6,
-                  bytestring >= 0.10.6.0,
-                  array >= 0.5.1.0,
+  build-depends:  base <= 5.0,
+                  hspec,
+                  QuickCheck,
+                  regex-base,
+                  regex-pcre,
+                  stringsearch,
+                  bytestring,
+                  array,
                   text,
                   regex-do
diff --git a/src/Regexdo/Pcre/Match.hs b/src/Regexdo/Pcre/Match.hs
--- a/src/Regexdo/Pcre/Match.hs
+++ b/src/Regexdo/Pcre/Match.hs
@@ -11,10 +11,11 @@
     see "Regexdo.Pcre.Result"
     for funs converting 'MatchArray' to something useful
 
-    'match' returns the first occurence - if any
+    'match' returns the first occurrence - if any
 
     -}
 
+
 class Match_ctr n h =>
             Match_cl n h where
 
@@ -28,6 +29,8 @@
    matchAll r0 (Haystack b0) = R.matchAll (r_ r0) b0
 
 
+
+
 -- | tweak Regex with options
 makeRegexOpts::Match_opt n =>
     [O.Comp] -> [O.Exec] -> Needle n -> Regex
@@ -58,8 +61,6 @@
 instance Match_cl Regex ByteString
 
 
-class Needle_ r where
-   r_::Needle r -> Regex
 
 instance Needle_ ByteString where
    r_ (Needle r0) = R.makeRegex r0
@@ -74,3 +75,6 @@
 -- | _ctr: constraint
 type Match_ctr n h = (R.Extract h, Needle_ n, R.RegexLike Regex h)
 type Match_opt n = R.RegexMaker Regex CompOption ExecOption n
+
+class Needle_ r where
+   r_::Needle r -> Regex
diff --git a/src/Regexdo/Pcre/Replace.hs b/src/Regexdo/Pcre/Replace.hs
--- a/src/Regexdo/Pcre/Replace.hs
+++ b/src/Regexdo/Pcre/Replace.hs
@@ -1,34 +1,129 @@
 module Regexdo.Pcre.Replace(
    ReplaceCase(..),
    Replace_cl(..),
-   replaceGroup,
-   replaceMatch
+   replaceMatch,
+   defaultReplacer,
+   Mr
    )  where
 
+import Data.Array
+import Data.ByteString
+import Prelude as P
 import qualified Data.ByteString as B
+import qualified Regexdo.Pcre.Option as O
 import qualified Text.Regex.Base.RegexLike as R
-
-import Regexdo.TypeDo
-import Regexdo.TypeRegex
+import Regexdo.Convert
 import Regexdo.Pcre.Match
 import Regexdo.Pcre.Result
-import qualified Regexdo.Pcre.Option as O
-import Regexdo.Convert
+import Regexdo.TypeDo
+import Regexdo.TypeRegex
 
-data ReplaceCase = Once | All | Utf8 | Multiline deriving Eq
 
-type Mm a = (Match_cl Regex a, Match_opt a)
-type Rm a = (Replace_cl' a, Match_cl Regex a)
+type Mr a = (Match_cl Regex a, Replace_cl' a, Match_opt a)
 
 
-addOpt::Match_opt a =>
-    Needle a -> [O.Comp] -> Needle Regex
-addOpt pat1 opt1 = Needle rx1
-    where rx1 = makeRegexOpts opt1 [] pat1
+class Replace_cl' a where
+   prefix::PosLen -> a -> a
+   suffix::PosLen -> a -> a
+   concat'::[a] -> a
+   toByteString'::a -> ByteString
+   toA::ByteString -> a
 
 
+class Replace_cl a where
+   replace::Mr a =>
+    [ReplaceCase] -> (Needle a, Replacement a) -> Haystack a -> a
+   replace cases0 (pat1,repl1) hay0 =
+        if isUtf8 cases0 then utfFn2
+        else fn2 (pat2 pat1,repl1) hay0
+        where fn1 = if P.elem All cases0 then rall else ronce
+              fn2 = if P.elem All cases0 then rall else ronce
+              utfFn2 = let res1 = fn1 (pat2 $ toByteString' <$> pat1, toByteString' <$> repl1) $ toByteString' <$> hay0
+                       in toA res1
+              pat2 pat1 = addOpt pat1 cOpt1
+              cOpt1 = comp cases0
 
-ronce::Rm a =>
+
+   replaceGroup::Mr a =>
+        [ReplaceCase] -> (Needle a, GroupReplacer a) -> Haystack a -> a
+   replaceGroup cases (pat1,repl1) = fn1 (pat2,repl1)
+        where pat2 = addOpt pat1 cOpt
+              cOpt = comp cases
+              fn1 = if P.elem All cases
+                     then rallGroup
+                     else ronceGroup
+
+{- ^
+   == dynamic group replace
+   custom replacer fn returns replacement value
+
+   >>> replacer::GroupReplacer String
+       replacer = defaultReplacer 3 tweak1
+             where tweak1 str1 = case str1 of
+                                  "101" -> "[A]"
+                                  "3" -> "[Be]"
+
+
+    'Once' vs 'All' options
+
+    >>> replaceGroup [Once] (Needle "(\\w)(=)(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
+
+        "a=[A] b=3 12"
+
+    >>> replaceGroup [All] (Needle "(\\w)(=)(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
+
+        "a=[A] b=[Be] 12"
+
+
+    == static replace for simple (no group) needle
+
+    >>> replace [Once,Utf8] (Needle "менее", Replacement  "более") (Haystack "менее менее")
+
+    "более менее"
+
+    >>> replace [Once,Utf8] (Needle "^a\\s", Replacement "A") (Haystack "a bc хол.гор.")
+
+    "Abc хол.гор."      -}
+
+instance Replace_cl String
+
+instance Replace_cl' String where
+   prefix pl1 = P.take $ fst pl1
+   suffix pl1 = P.drop (pos1 + len1)
+      where pos1 = fst pl1
+            len1 = snd pl1
+   concat' = P.concat
+   toByteString' = toByteString
+   toA = toString
+
+
+instance Replace_cl B.ByteString
+
+instance Replace_cl' B.ByteString where
+   prefix pl1 = B.take $ fst pl1
+   suffix pl1 = B.drop (pos1 + len1)
+      where pos1 = fst pl1
+            len1 = snd pl1
+   concat' = B.concat
+   toByteString' = id
+   toA = id
+
+
+-- | use in your custom 'GroupReplacer' passed to 'replaceGroup'
+--
+-- see example replacer above or use 'defaultReplacer'
+--
+replaceMatch::Replace_cl' a =>
+        (R.MatchOffset, R.MatchLength) ->
+        (a, a)  -- ^ (new val, acc passed to 'GroupReplacer')
+        -> a    -- ^ new acc
+replaceMatch pl1 (repl1, bs_str1) =
+     concat' [prefix1,repl1,suffix1]
+     where   prefix1 = prefix pl1 bs_str1
+             suffix1 = suffix pl1 bs_str1
+
+--  static
+ronce::Mr a =>
     (Needle Regex, Replacement a) -> Haystack a -> a
 ronce (pat1, Replacement repl1) body1@(Haystack bs_str1) =
       let pl2 = do
@@ -39,15 +134,14 @@
          Just pl_arr -> firstGroup pl_arr (repl1,bs_str1)
 
 
-rall::Rm a =>
+rall::Mr a =>
     (Needle Regex, Replacement a) -> Haystack a -> a
 rall (pat1, Replacement repl1) body1@(Haystack bs_str1) =
       let pl_arr_arr1 = do
                let m1 = matchAll pat1 body1
                poslen m1
           folderFn pl_arr acc1 = firstGroup pl_arr (repl1,acc1)
-      in foldr folderFn bs_str1 pl_arr_arr1
-
+      in P.foldr folderFn bs_str1 pl_arr_arr1
 
 
 firstGroup::Replace_cl' a =>
@@ -55,55 +149,22 @@
 firstGroup (pl1:_) r1@(repl1,bs_str1) = replaceMatch pl1 r1
 
 
--- | use in your custom 'GroupReplacer' passed to 'replaceGroup'
---
--- see example replacer above
---
-replaceMatch::Replace_cl' a =>
-    (R.MatchOffset, R.MatchLength) ->
-        (a, a)  -- ^ (new val, acc passed to 'GroupReplacer')
-        -> a
-replaceMatch pl1 (repl1, bs_str1) =
-     concat' [prefix1,repl1,suffix1]
-     where   prefix1 = prefix pl1 bs_str1
-             suffix1 = suffix pl1 bs_str1
-
-
-{- | == dynamic group replace
-   custom replacer fn returns replacement value
-
-   >>> replacer::GroupReplacer String
-       replacer marr1 acc1 = case val1 of
-                              "101" -> fn1 "[A]"
-                              "3" -> fn1 "[Be]"
-       where ol1 = marr1 ! 3 :: (MatchOffset, MatchLength)
-             val1 = extract ol1 acc1
-             fn1 str1 = replaceMatch ol1 (str1,acc1)
-
-    see 'extract'
-
-    below test compares 'Once' vs 'All' options
+--  dynamic
+{- | replace with a tweak to specified (by idx) group match
 
-    >>> groupReplace::IO()
-        groupReplace =  hspec $ do
-            describe "Pcre.Replace group" $ do
-                it "Once" $ do
-                   runFn1 [Once] `shouldBe` "a=[A] b=3 12"
-                it "All" $ do
-                   runFn1 [All] `shouldBe` "a=[A] b=[Be] 12"
-                where runFn1 opts1 =
-                         let   rx1 = Needle "(\\w)(=)(\\d{1,3})"
-                               body1 = Haystack "a=101 b=3 12"
-                         in replaceGroup opts1 (rx1,replacer) body1
--}
-replaceGroup::Mm a =>
-    [ReplaceCase]->(Needle a,GroupReplacer a) -> Haystack a -> a
-replaceGroup cases (pat1,repl1) = fn1 (pat2,repl1)
-    where pat2 = addOpt pat1 cOpt
-          cOpt = comp cases
-          fn1 = if elem All cases
-                 then rallGroup
-                 else ronceGroup
+    see 'defaultReplacer' source for hints: how to write custom replacer
+     -}
+defaultReplacer::(Replace_cl' a, R.Extract a) =>
+        Int         -- ^ idx of match within a group
+        -> (a -> a) -- ^ (group match -> replacement) tweak
+            -> GroupReplacer a
+defaultReplacer idx0 tweak0 (ma0::MatchArray) acc0 =
+        if idx0 >= P.length ma0 then acc0     --  safety catch
+        else fn1 val1
+       where poslen1 = ma0 ! idx0 :: (R.MatchOffset, R.MatchLength)
+             val1 = extract poslen1 acc0
+             fn1 str1 = replaceMatch poslen1 (str2,acc0)
+                        where str2 = tweak0 str1
 
 
 ronceGroup::Match_cl Regex a =>
@@ -119,77 +180,22 @@
     (Needle Regex, GroupReplacer a) -> Haystack a -> a
 rallGroup (pat1, repl1) body1@(Haystack bs_str1) =
     let marrList1 = matchAll pat1 body1
-    in foldr repl1 bs_str1 marrList1
-
-
-
-class Replace_cl a where
-   replace::[ReplaceCase] -> (Needle a, Replacement a) -> Haystack a -> a
-
-
-class Replace_cl' a where
-   prefix::PosLen -> a -> a
-   suffix::PosLen -> a -> a
-   concat'::[a] -> a
-
-
-{- |
-    >>> replace [Once,Utf8] (Needle "поп", Replacement  "крестьянин") (Haystack "у попа была собака")
-
-    "у крестьянина была собака"
-
-    >>> replace [Once,Utf8] (Needle "^a\\s", Replacement "A") (Haystack "a bc хол.гор.")
-
-    "Abc хол.гор."
-
- -}
-
-instance Replace_cl String where
-   replace::[ReplaceCase] -> (Needle String, Replacement String) -> Haystack String -> String
-   replace cases0 (pat1,repl1) hay0 = if isUtf8 cases0 then
-        let res1 = fn1 (pat2 $ toByteString <$> pat1, toByteString <$> repl1) $ toByteString <$> hay0
-        in toString res1
-        else fn2 (pat2 pat1,repl1) hay0
-        where pat2 pat1 = addOpt pat1 cOpt
-              cOpt = comp cases0
-              fn1 = if elem All cases0 then rall else ronce
-              fn2 = if elem All cases0 then rall else ronce
-
-
-instance Replace_cl' String where
-   prefix pl1 = take $ fst pl1
-   suffix pl1 = drop (pos1 + len1)
-      where pos1 = fst pl1
-            len1 = snd pl1
-   concat' = concat
+    in P.foldr repl1 bs_str1 marrList1
 
 
 
-instance Replace_cl B.ByteString where
-   replace::[ReplaceCase] -> (Needle B.ByteString, Replacement B.ByteString) ->
-        Haystack B.ByteString -> B.ByteString
-   replace cases0 (pat1,repl1) hay0 = fn1 (pat2,repl1) hay0
-    where pat2 = addOpt pat1 cOpt
-          cOpt = comp cases0
-          fn1 = if elem All cases0
-                then rall
-                else ronce
-
-
-instance Replace_cl' B.ByteString where
-   prefix pl1 = B.take $ fst pl1
-   suffix pl1 = B.drop (pos1 + len1)
-      where pos1 = fst pl1
-            len1 = snd pl1
-   concat' = B.concat
+addOpt::Match_opt a =>
+    Needle a -> [O.Comp] -> Needle Regex
+addOpt pat1 opt1 = Needle rx1
+    where rx1 = makeRegexOpts opt1 [] pat1
 
 
 comp::[ReplaceCase]-> [O.Comp]
-comp = map mapFn . filter filterFn
-   where filterFn o1 = o1 `elem` [Utf8,Multiline]
+comp = P.map mapFn . P.filter filterFn
+   where filterFn o1 = o1 `P.elem` [Utf8,Multiline]
          mapFn Utf8 = O.Utf8
          mapFn Multiline = O.Multiline
 
 
 isUtf8::[ReplaceCase] -> Bool
-isUtf8 case0 = Utf8 `elem` case0
+isUtf8 case0 = Utf8 `P.elem` case0
diff --git a/src/Regexdo/Search.hs b/src/Regexdo/Search.hs
--- a/src/Regexdo/Search.hs
+++ b/src/Regexdo/Search.hs
@@ -14,7 +14,7 @@
     splitFront) where
 import qualified Data.ByteString.Search as S
 
-import Regexdo.TypeDo
+import Regexdo.TypeDo hiding (replace)
 import Data.ByteString as B hiding (break, breakEnd, split)
 import qualified Data.ByteString.Lazy as L
 import Prelude hiding (break)
@@ -23,7 +23,7 @@
 -- front:      a \nb
 -- end:        a\n b
 
-{- | lose needle
+{- | (front, end)  : drop needle
 
     >>> break (Needle ":") (Haystack "0123:oid:90")
 
diff --git a/src/Regexdo/Trim.hs b/src/Regexdo/Trim.hs
--- a/src/Regexdo/Trim.hs
+++ b/src/Regexdo/Trim.hs
@@ -1,11 +1,10 @@
 module Regexdo.Trim where
 
-import Regexdo.Pcre.Replace(replace,ReplaceCase(All))
 import Regexdo.TypeDo
 import Data.Char(isSpace)
 import qualified Data.ByteString as B
 import Regexdo.Convert
-
+import Regexdo.Pcre.Replace
 
 {- | removes leading and trailing spaces and tabs   -}
 
diff --git a/src/Regexdo/TypeDo.hs b/src/Regexdo/TypeDo.hs
--- a/src/Regexdo/TypeDo.hs
+++ b/src/Regexdo/TypeDo.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE DeriveFunctor #-}
 module Regexdo.TypeDo where
 
 import Text.Regex.Base.RegexLike
@@ -13,3 +12,11 @@
 data Replacement r = Replacement r deriving (Functor)     --    Bs, String
 
 type PosLen = (MatchOffset, MatchLength)
+
+
+data ReplaceCase = Once     -- ^ may be omitted
+                | All       -- ^ if both Once and All are passed, All prevails
+                | Utf8
+                | Multiline deriving Eq
+
+
diff --git a/test/TestRegex/Format.hs b/test/TestRegex/Format.hs
--- a/test/TestRegex/Format.hs
+++ b/test/TestRegex/Format.hs
@@ -8,6 +8,8 @@
 main::IO()
 main = hspec $ do
        describe "Habase.Bin.Format" $ do
+          it "list arg 0,0 repl []" $ do
+            format "на первое {0}, на второе {0}" ([]::[String]) `shouldBe` "на первое {0}, на второе {0}"
           it "list arg 0,0" $ do
             format "на первое {0}, на второе {0}" ["перловка"] `shouldBe` "на первое перловка, на второе перловка"
           it "list arg 0,1" $ do
diff --git a/test/TestRegex/Pcre.hs b/test/TestRegex/Pcre.hs
--- a/test/TestRegex/Pcre.hs
+++ b/test/TestRegex/Pcre.hs
@@ -3,9 +3,10 @@
 
 import Test.Hspec
 import Regexdo.TypeDo
-import qualified Regexdo.Pcre.Match as M
+import Regexdo.Pcre.Match as M
 import qualified Regexdo.Pcre.Result as R
 import Regexdo.Convert
+
 
 
 main::IO()
diff --git a/test/TestRegex/Replace.hs b/test/TestRegex/Replace.hs
--- a/test/TestRegex/Replace.hs
+++ b/test/TestRegex/Replace.hs
@@ -2,13 +2,11 @@
 module TestRegex.Replace where
 
 import Test.Hspec
-import Data.Array((!))
 import Regexdo.TypeDo
 
 import Regexdo.Pcre.Replace
 import Regexdo.Convert
 import Data.ByteString as B
-import Text.Regex.Base.RegexLike
 
 
 main::IO()
@@ -22,9 +20,18 @@
 doc::IO()
 doc = hspec $ do
        describe "Pcre.Replace doc" $ do
-          it "replace" $ do
-            replace [Once,Utf8] (Needle "поп", Replacement  "крестьянин") (Haystack "у попа была собака") `shouldBe` "у крестьянина была собака"
-
+          it "replaceGroup 1" $ do
+            replaceGroup [Once] (Needle "(\\w)(=)(\\d{1,3})", replacer) (Haystack "a=101 b=3 12")
+                `shouldBe` "a=[A] b=3 12"
+          it "replaceGroup 2" $ do
+            replaceGroup [All] (Needle "(\\w)(=)(\\d{1,3})", replacer) (Haystack "a=101 b=3 12")
+                `shouldBe` "a=[A] b=[Be] 12"
+          it "replace 3" $ do
+            replace [Once,Utf8] (Needle "менее", Replacement  "более") (Haystack "менее менее")
+                `shouldBe` "более менее"
+          it "replace 4" $ do
+            replace [Once,Utf8] (Needle "^a\\s", Replacement "A") (Haystack "a bc хол.гор.")
+                `shouldBe` "Abc хол.гор."
 
 
 onceUtf8::IO()
@@ -73,10 +80,7 @@
 
 
 replacer::GroupReplacer String
-replacer marr1 acc1 = case val1 of
-                          "101" -> fn1 "[A]"
-                          "3" -> fn1 "[Be]"
-   where ol1 = marr1 ! 3 :: (MatchOffset, MatchLength)
-         val1 = extract ol1 acc1
---         !val2 = trace (show val1) val1
-         fn1 str1 = replaceMatch ol1 (str1,acc1)
+replacer = defaultReplacer 3 tweak1
+      where tweak1 str1 = case str1 of
+                              "101" -> "[A]"
+                              "3" -> "[Be]"
diff --git a/test/TestRegex/StringSearch.hs b/test/TestRegex/StringSearch.hs
--- a/test/TestRegex/StringSearch.hs
+++ b/test/TestRegex/StringSearch.hs
@@ -4,7 +4,7 @@
 import Test.Hspec
 import Control.Exception (evaluate)
 import Regexdo.TypeDo
-import Regexdo.Search
+import Regexdo.Search as S
 import qualified Data.ByteString as B
 import Regexdo.Convert
 
@@ -21,7 +21,7 @@
           it "break end" $ do
             breakEnd (Needle "\n") (Haystack "a\nbc\nde") `shouldBe` ("a\n", "bc\nde")
           it "replace" $ do
-            replace (Needle "\n") (Replacement ",") (Haystack "a\nbc\nde") `shouldBe` "a,bc,de"
+            S.replace (Needle "\n") (Replacement ",") (Haystack "a\nbc\nde") `shouldBe` "a,bc,de"
           it "split" $ do
             split (Needle "\n") (Haystack "a\nbc\nde") `shouldBe` ["a", "bc", "de"]
           it "split_sp" $ do
@@ -42,7 +42,7 @@
           it "break end" $ do
             evaluate (errFn breakEnd) `shouldThrow` anyException
           it "replace" $ do
-            evaluate (replace (Needle B.empty) with body) `shouldThrow` anyException
+            evaluate (S.replace (Needle B.empty) with body) `shouldThrow` anyException
           it "split" $ do
             evaluate (errFn split) `shouldThrow` anyException
           it "split end" $ do
@@ -62,7 +62,7 @@
                break1 = break pat body
                breakFront1 = breakFront pat body
                breakEnd1 = breakEnd pat body
-               replace1 = replace pat with body
+               replace1 = S.replace pat with body
                split1 = split pat body
                split_sp1 = split pat_sp body_sp
                splitFront1 = splitFront pat body
