diff --git a/regex-do.cabal b/regex-do.cabal
--- a/regex-do.cabal
+++ b/regex-do.cabal
@@ -1,7 +1,7 @@
 name:                regex-do
-version:             1.1
-synopsis:            PCRE regex funs
-description:         Convenience functions to search, replace, format String | ByteString with PCRE regex
+version:             1.3
+synopsis:            PCRE wrapper
+description:         search, replace, format String | ByteString with PCRE regex Utf8-safe
 author:              Imants Cekusins
 maintainer:          Imants Cekusins
 category:            Regex, Search, String
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
@@ -49,15 +49,15 @@
 -}
 
 instance Match_cl String String
--- | this instance accepts regex 'String'
+-- | accepts regex 'String'
 instance Match_cl String ByteString
--- | this instance accepts regex 'ByteString'
+-- | accepts regex 'ByteString'
 instance Match_cl ByteString ByteString
--- | this instance accepts regex 'ByteString'
+-- | accepts regex 'ByteString'
 instance Match_cl ByteString String
--- | this instance accepts 'Regex' made with 'makeRegexOpts'
+-- | accepts 'Regex' made with 'makeRegexOpts'
 instance Match_cl Regex String
--- | this instance accepts 'Regex' made with 'makeRegexOpts'
+-- | accepts 'Regex' made with 'makeRegexOpts'
 instance Match_cl Regex ByteString
 
 
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
@@ -3,10 +3,11 @@
    Replace_cl(..),
    replaceMatch,
    defaultReplacer,
+   getGroup,
    Mr
    )  where
 
-import Data.Array
+import Data.Array as A
 import Data.ByteString
 import Prelude as P
 import qualified Data.ByteString as B
@@ -26,6 +27,7 @@
    prefix::PosLen -> a -> a
    suffix::PosLen -> a -> a
    concat'::[a] -> a
+   len'::a -> Int
    toByteString'::a -> ByteString
    toA::ByteString -> a
 
@@ -58,33 +60,34 @@
    custom replacer fn returns replacement value
 
    >>> replacer::GroupReplacer String
-       replacer = defaultReplacer 3 tweak1
+       replacer = defaultReplacer 1 tweak1
              where tweak1 str1 = case str1 of
-                                  "101" -> "[A]"
-                                  "3" -> "[Be]"
-
+                                   "101" -> "[сто один]"
+                                   "3" -> "[three]"
+                                   otherwise -> trace str1 "?"
 
     'Once' vs 'All' options
 
-    >>> replaceGroup [Once] (Needle "(\\w)(=)(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
+    >>> replaceGroup [Once,Utf8] (Needle "\\w=(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
 
-        "a=[A] b=3 12"
+        "a=[сто один] b=3 12"
 
-    >>> replaceGroup [All] (Needle "(\\w)(=)(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
+    >>> replaceGroup [All,Utf8] (Needle "\\w=(\\d{1,3})", replacer) $ Haystack "a=101 b=3 12"
 
-        "a=[A] b=[Be] 12"
+        "a=[сто один] b=[three] 12"
 
 
     == static replace for simple (no group) needle
 
-    >>> replace [Once,Utf8] (Needle "менее", Replacement  "более") (Haystack "менее менее")
+    >>> replace [Once,Utf8] (Needle "менее", Replacement  "более") $ Haystack "менее менее"
 
     "более менее"
 
-    >>> replace [Once,Utf8] (Needle "^a\\s", Replacement "A") (Haystack "a bc хол.гор.")
+    >>> replace [Once,Utf8] (Needle "^a\\s", Replacement "A") $ Haystack "a bc хол.гор."
 
     "Abc хол.гор."      -}
 
+
 instance Replace_cl String
 
 instance Replace_cl' String where
@@ -95,6 +98,7 @@
    concat' = P.concat
    toByteString' = toByteString
    toA = toString
+   len' = P.length
 
 
 instance Replace_cl B.ByteString
@@ -107,81 +111,109 @@
    concat' = B.concat
    toByteString' = id
    toA = id
+   len' = B.length
 
 
--- | 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) =
+ronce (pat1, Replacement repl1) h1@(Haystack h0) =
       let pl2 = do
-               let m1 = match pat1 body1
+               let m1 = match pat1 h1
                poslen m1
       in case pl2 of
-         Nothing -> bs_str1
-         Just pl_arr -> firstGroup pl_arr (repl1,bs_str1)
+         Nothing -> h0
+         Just lpl1 -> firstGroup lpl1 (repl1, h0)
 
 
 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 P.foldr folderFn bs_str1 pl_arr_arr1
+rall (pat1, Replacement repl1) h1@(Haystack h0) =
+      let lpl1 = do
+               let m1 = matchAll pat1 h1
+               poslen m1::[[PosLen]]
+          foldFn1 lpl1 acc1 = firstGroup lpl1 (repl1,acc1)
+      in P.foldr foldFn1 h0 lpl1
 
 
-firstGroup::Replace_cl' a =>
+firstGroup::(Replace_cl' a) =>
     [PosLen] -> (a,a) -> a
-firstGroup (pl1:_) r1@(repl1,bs_str1) = replaceMatch pl1 r1
+firstGroup (pl0:_) r1@(new0,a0) = acc_haystack $ replaceMatch pl0 (new0, acc1)
+    where acc1 = ReplaceAcc {
+                    acc_haystack = a0,
+                    position_adj = 0
+                    }
 
 
 --  dynamic
-{- | replace with a tweak to specified (by idx) group match
+{- | you can write a custom replacer. This is only one common use case.
 
-    see 'defaultReplacer' source for hints: how to write custom replacer
-     -}
+    Replaces specified (by idx) group match with tweaked value.     -}
 defaultReplacer::(Replace_cl' a, R.Extract a) =>
-        Int         -- ^ idx of match within a group
+        Int         -- ^ group idx
         -> (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)
+defaultReplacer idx0 tweak0 (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
+
+    call from your custom 'GroupReplacer' passed to 'replaceGroup'
+    -}
+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_haystack acc0
+
+
+adjustPoslen::PosLen -> ReplaceAcc a -> PosLen
+adjustPoslen (p0,l0) acc0  = (p0 + position_adj acc0, l0)
+
+
 ronceGroup::Match_cl Regex a =>
     (Needle Regex, GroupReplacer a) -> Haystack a -> a
-ronceGroup (pat1, repl1) body1@(Haystack bs_str1) =
-     let m1 = match pat1 body1
+ronceGroup (pat1, repl1) h1@(Haystack h0) =
+     let m1 = match pat1 h1::Maybe MatchArray
      in case m1 of
-            Nothing -> bs_str1
-            Just marr1 -> repl1 marr1 bs_str1
+            Nothing -> h0
+            Just ma1 -> let a1 = ReplaceAcc {
+                                    acc_haystack = h0,
+                                    position_adj = 0
+                                    }
+                        in acc_haystack $ repl1 ma1 a1
 
 
 rallGroup::Match_cl Regex a =>
     (Needle Regex, GroupReplacer a) -> Haystack a -> a
-rallGroup (pat1, repl1) body1@(Haystack bs_str1) =
-    let marrList1 = matchAll pat1 body1
-    in P.foldr repl1 bs_str1 marrList1
+rallGroup (pat1, repl1) h1@(Haystack h0) =
+    let ma1 = matchAll pat1 h1::[MatchArray]
+        acc1 = ReplaceAcc { acc_haystack = h0, position_adj = 0 }
+    in acc_haystack $ P.foldl (flip repl1) acc1 ma1
 
+
+{- | call from your custom 'GroupReplacer' passed to 'replaceGroup'
+
+     see example replacer above     -}
+replaceMatch::Replace_cl' a =>
+        PosLen      -- ^ replaced
+        -> (a, ReplaceAcc a)  -- ^ (new val, acc passed to 'GroupReplacer')
+        -> ReplaceAcc a    -- ^ new acc
+replaceMatch pl0@(_,l0) (new0, acc0) = ReplaceAcc {
+                    acc_haystack = acc1,
+                    position_adj = position_adj acc0 + l1 - l0
+                    }
+     where  pl1 = adjustPoslen pl0 acc0
+            prefix1 = prefix pl1 $ acc_haystack acc0
+            suffix1 = suffix pl1 $ acc_haystack acc0
+            acc1 = concat' [prefix1, new0, suffix1]
+            l1 = len' new0
 
 
 addOpt::Match_opt a =>
diff --git a/src/Regexdo/Search.hs b/src/Regexdo/Search.hs
--- a/src/Regexdo/Search.hs
+++ b/src/Regexdo/Search.hs
@@ -1,8 +1,8 @@
-{- | from stringsearch package
+{- | wraps functions from stringsearch package
 
     this module uses newtypes for args plus function names are tweaked
 
-    regex is treated as ordinary String. Do not use regex.
+    regex is treated as ordinary String
     -}
 module Regexdo.Search
     (break,
diff --git a/src/Regexdo/TypeDo.hs b/src/Regexdo/TypeDo.hs
--- a/src/Regexdo/TypeDo.hs
+++ b/src/Regexdo/TypeDo.hs
@@ -3,7 +3,13 @@
 import Text.Regex.Base.RegexLike
 
 -- pcre
-type GroupReplacer acc = (MatchArray -> acc -> acc) -- MatchArray -> acc -> acc
+type GroupReplacer a = (MatchArray -> ReplaceAcc a -> ReplaceAcc a) -- MatchArray -> acc -> acc
+
+
+data ReplaceAcc a = ReplaceAcc {
+    acc_haystack::a,   -- ^ wip Haystack
+    position_adj::Int
+    }
 
 
 -- stringsearch, Pcre.Replace
diff --git a/test/TestRegex/Replace.hs b/test/TestRegex/Replace.hs
--- a/test/TestRegex/Replace.hs
+++ b/test/TestRegex/Replace.hs
@@ -7,6 +7,7 @@
 import Regexdo.Pcre.Replace
 import Regexdo.Convert
 import Data.ByteString as B
+import Debug.Trace
 
 
 main::IO()
@@ -21,11 +22,11 @@
 doc = hspec $ do
        describe "Pcre.Replace doc" $ do
           it "replaceGroup 1" $ do
-            replaceGroup [Once] (Needle "(\\w)(=)(\\d{1,3})", replacer) (Haystack "a=101 b=3 12")
-                `shouldBe` "a=[A] b=3 12"
+            replaceGroup [Once,Utf8] (Needle "\\w=(\\d{1,3})", replacer) (Haystack "a=101 b=3 12")
+                `shouldBe` "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"
+            replaceGroup [All,Utf8] (Needle "\\w=(\\d{1,3})", replacer) (Haystack "a=101 b=3 12")
+                `shouldBe` "a=[сто один] b=[three] 12"
           it "replace 3" $ do
             replace [Once,Utf8] (Needle "менее", Replacement  "более") (Haystack "менее менее")
                 `shouldBe` "более менее"
@@ -70,17 +71,18 @@
 groupReplace =  hspec $ do
          describe "Pcre.Replace group" $ do
             it "Once" $ do
-               runFn1 [Once] `shouldBe` "a=[A] b=3 12"
+               runFn1 [Once,Utf8] `shouldBe` "a=[сто один] b=3 12"
             it "All" $ do
-               runFn1 [All] `shouldBe` "a=[A] b=[Be] 12"
+               runFn1 [All,Utf8] `shouldBe` "a=[сто один] b=[three] 12"
             where runFn1 opts1 =
-                     let   rx1 = Needle "(\\w)(=)(\\d{1,3})"
+                     let   rx1 = Needle "\\w=(\\d{1,3})"
                            body1 = Haystack "a=101 b=3 12"
                      in replaceGroup opts1 (rx1,replacer) body1
 
 
 replacer::GroupReplacer String
-replacer = defaultReplacer 3 tweak1
+replacer = defaultReplacer 1 tweak1
       where tweak1 str1 = case str1 of
-                              "101" -> "[A]"
-                              "3" -> "[Be]"
+                              "101" -> "[сто один]"
+                              "3" -> "[three]"
+                              otherwise -> trace str1 "?"
diff --git a/test/TestRegex/TestTrim.hs b/test/TestRegex/TestTrim.hs
--- a/test/TestRegex/TestTrim.hs
+++ b/test/TestRegex/TestTrim.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE OverloadedStrings #-}
 module TestRegex.TestTrim where
 
 import Test.Hspec
@@ -11,8 +12,7 @@
 main = hspec $ do
           describe "Habase.Bin.Bistro" $ do
               it "trim" $ trace (show trimmed1) trimmed1 `shouldBe` (toByteString trimmed)
-              it "trim 2" $
-                trim sTrim `shouldBe` "aiy  \n  pdsodfg987"
-    where sTrim = "    aiy  \n  pdsodfg987   "
+              it "trim 2" $ trim sTrim `shouldBe` "aiy  \n  pdsodfg987"
+    where sTrim = " \t aiy  \n  pdsodfg987  \t\t   "::String
           trimmed1 = trim $ toByteString sTrim
           trimmed = (T.unpack . T.strip . T.pack) sTrim
