packages feed

regex-do 1.0 → 1.1

raw patch · 10 files changed

+198/−169 lines, 10 filesdep ~QuickCheckdep ~arraydep ~base

Dependency ranges changed: QuickCheck, array, base, bytestring, hspec, regex-base, regex-pcre, stringsearch

Files

regex-do.cabal view
@@ -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
src/Regexdo/Pcre/Match.hs view
@@ -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
src/Regexdo/Pcre/Replace.hs view
@@ -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
src/Regexdo/Search.hs view
@@ -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") 
src/Regexdo/Trim.hs view
@@ -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   -} 
src/Regexdo/TypeDo.hs view
@@ -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++
test/TestRegex/Format.hs view
@@ -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
test/TestRegex/Pcre.hs view
@@ -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()
test/TestRegex/Replace.hs view
@@ -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]"
test/TestRegex/StringSearch.hs view
@@ -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