packages feed

regex-do 2.3 → 2.4

raw patch · 9 files changed

+225/−98 lines, 9 files

Files

changelog.md view
@@ -1,3 +1,6 @@+#####   2.4+  refactor Replace: remove ReplaceCase. Use Once | All hints instead  +  #####   2.3    include missing TestReplaceOpen      @@ -26,4 +29,30 @@  #####   1.7    add MatchSame-                                   ++#####   1.6+  rollup all match fns into one class+  add Matchf, Pad++#####   1.5+  rename Match class -> ExplicitMatch++#####   1.4+  *API changes*+  changed namespace                                         ++#####   1.3+  fix bug in replace+  docs+  base version constraint+  +    +there is no 1.2 version+  +#####   1.1+  refactor Replace  +  ! buggy replace++#####   1.0+  initial version +  ! buggy replace         
regex-do.cabal view
@@ -1,5 +1,5 @@ name:                regex-do-version:             2.3+version:             2.4 synopsis:            PCRE wrapper description:         format, search, replace (String | ByteString) with PCRE regex. Utf8-safe author:              Imants Cekusins
src/Text/Regex/Do/Pcre/Match.hs view
@@ -6,8 +6,6 @@  import qualified Text.Regex.Base.RegexLike as R hiding (makeRegex) import Text.Regex.Do.Type.Do-import Text.Regex.Do.Pcre.Option as O-import Text.Regex.Do.Type.Reexport import Text.Regex.Do.Pcre.Matchf as F import Text.Regex.PCRE.Wrap() import Text.Regex.Do.Type.Regex_@@ -72,12 +70,3 @@ instance Rx_ a b => Match a b [[PosLen]] where     match = poslen_ ----- | tweak Regex with options-makeRegexOpts::Opt_ a =>-    [O.Comp] -> [O.Exec] -> Pattern a -> Regex-makeRegexOpts comp0 exec0 (Pattern pat0) = rx1-   where c1 = O.comp comp0-         e1 = O.exec exec0-         rx1 = R.makeRegexOpts c1 e1 pat0
src/Text/Regex/Do/Pcre/Option.hs view
@@ -9,20 +9,100 @@ import qualified Text.Regex.PCRE.ByteString as B  +-- | <http://www.pcre.org/pcre.txt pcre man pages>+ data Comp = Blank       -- ^ 'B.compBlank'-            | Anchored  -- ^ 'B.compAnchored'-            | Caseless  -- ^ 'B.compCaseless'-            | Dotall    -- ^ 'B.compDotAll'-            | Multiline -- ^ 'B.compMultiline'-            | Utf8      -- ^ 'B.compUTF8'-            | Ungreedy  -- ^ 'B.compUngreedy'-   deriving Enum+            | Anchored  {- ^ 'B.compAnchored' +            the pattern is forced to be "anchored", that is, it+       is  constrained to match only at the first matching point in the string+       that is being searched (the "subject string"). +       This effect can also  be achieved  by appropriate constructs in the pattern itself. -}++            | Caseless  {- ^ 'B.compCaseless'++            letters in the pattern match both upper  and  lower case  letters.++            It  is  equivalent  to  Perl's /i option, and it can be changed within a pattern by a (?i) option setting.++       In UTF-8 mode,  PCRE always  understands the concept of case for characters whose values are+       less than 128, so caseless matching is always possible. For  characters with  higher  values,  the concept of case is supported if PCRE is compiled with Unicode property support.+        If you want  to use  caseless  matching  for  characters 128 and above, you must ensure+       that PCRE is compiled with Unicode property support  as  well  as  with UTF-8 support.   -}++            | Dotall    {- ^ 'B.compDotAll'++            a dot metacharacter in the pattern matches a  character of any value,+            including one that indicates a newline.++            However, it only ever matches one character, even if newlines are  coded  as  CRLF.++       Without  this option, a dot does not match when the current position is+       at a newline.++       This option is equivalent to Perl's /s option, and it can be  changed within a pattern by a (?s) option setting.++       A negative class such as [^a] always matches newline characters, independent of the setting of this option. -}++            | Multiline {- ^ 'B.compMultiline'++            By default, for the purposes of matching "start of line"  and  "end  of+       line", PCRE treats the subject string as consisting of a single line of+       characters, even if it actually contains newlines. The "start of  line"+       metacharacter (^) matches only at the start of the string, and the "end+       of line" metacharacter ($) matches only at the end of  the  string,  or+       before  a terminating newline (except when PCRE_DOLLAR_ENDONLY is set).+       Note, however, that unless PCRE_DOTALL  is  set,  the  "any  character"+       metacharacter  (.)  does not match at a newline. This behaviour (for ^,+       $, and dot) is the same as Perl.++       When PCRE_MULTILINE it is set, the "start of line" and  "end  of  line"+       constructs  match  immediately following or immediately before internal+       newlines in the subject string, respectively, as well as  at  the  very+       start  and  end.++       This is equivalent to Perl's /m option, and it can be+       changed within a pattern by a (?m) option setting.++       If there are no newlines  in  a  subject string, or no occurrences of ^ or $ in a pattern,+       setting PCRE_MULTILINE has no effect.    -}++            | Utf8      {- ^ 'B.compUTF8'++            This option causes PCRE to regard both the pattern and the  subject  as+       strings of UTF-8 characters instead of single-byte strings. However, it+       is available only when PCRE is built to include UTF  support.  If  not,+       the  use  of  this option provokes an error. Details of how this option+       changes the behaviour of PCRE are given in the pcreunicode page.     -}++            | Ungreedy  {- ^ 'B.compUngreedy'++            This  option  inverts  the "greediness" of the quantifiers so that they+       are not greedy by default, but become greedy if followed by "?".++       It can also be set by a (?U) option setting within the pattern.  -}+   deriving (Eq,Ord,Enum)++ data Exec = BlankE  -- ^ 'B.execBlank'-            | NotEmpty  -- ^ 'B.execNotEmpty'-            | Partial   -- ^ 'B.execPartial'-   deriving Enum+            | NotEmpty  {- ^ 'B.execNotEmpty'++            An empty string is not considered to be a valid match if this option is+       set. If there are alternatives in the pattern, they are tried.  If  all+       the  alternatives  match  the empty string, the entire match fails. For+       example, if the pattern++         a?b?++       is applied to a string not beginning with "a" or  "b",  it  matches  an+       empty  string at the start of the subject. With PCRE_NOTEMPTY set, this+       match is not valid, so PCRE searches further into the string for occurrences of "a" or "b".        -}++            | Partial   {- ^ 'B.execPartial'++            see PCREPARTIAL(3)  in <http://www.pcre.org/pcre.txt pcre man pages>    -}+   deriving (Eq,Ord,Enum)   compOpt::Comp -> B.CompOption
src/Text/Regex/Do/Pcre/Replace.hs view
@@ -1,12 +1,10 @@-module Text.Regex.Do.Pcre.Replace(-    replace,-    ReplaceCase_(..))  where+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.Pcre.Match as M import Text.Regex.Do.Type.Do import Text.Regex.Do.Type.Reexport import Text.Regex.Do.Pcre.Matchf@@ -14,8 +12,16 @@ 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' @@ -28,11 +34,11 @@      'Once' vs 'All' options -    >>> replace [Once,Utf8] (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"          "a=[сто один] b=3 12" -    >>> replace [All,Utf8] (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"          "a=[сто один] b=[three] 12" @@ -41,69 +47,81 @@      for no-regex 'ByteString' replacement see "Text.Regex.Do.Split" -    >>> replace [Once,Utf8] (Pattern "менее") (Replacement  "более") $ Body "менее менее"+    >>> replace (Once[Utf8]) (Pattern "менее") (Replacement  "более") $ Body "менее менее"      "более менее" -    >>> replace [Once,Utf8] (Pattern "^a\\s") (Replacement "A") $ Body "a bc хол.гор."+    >>> 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 -replace::(Rx_ a a, ReplaceCase_ r a, Opt_ a) =>-    [ReplaceCase] -> Pattern a -> r a -> Body a -> a-replace case0 p0 r0 b0 = replace_ case0 p1 r0 b0-    where opt1 = comp case0-          p1 = addOpt p0 opt1 +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 --- | implementation detail for the curious-class ReplaceCase_ r a where-    replace_::[ReplaceCase] -> Pattern Regex -> r a -> Body a -> a -instance ReplaceCase_ Replacement String where-    replace_ case0 p0 r0 b0 =-        let ma1 = marray_ p0 b1::Maybe MatchArray-            ma2 = marray_ p0 b1::[MatchArray]+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-            isAll1 = All `P.elem` case0-            isUtf1 = Utf8 `P.elem` case0-            bs1 = if isAll1 then O.replace ma2 r1 b1-                  else O.replace ma1 r1 b1+            isUtf1 = O.Utf8 `P.elem` opt1+            bs1 = O.replace ma2 r1 b1+            p1 = rx' p0 opt1         in if isUtf1 then toString bs1-            else vanilla_replace case0 p0 r0 b0+            else vanilla_all p1 r0 b0  -instance ReplaceCase_ Replacement ByteString where-    replace_ = vanilla_replace+instance Regex_ rx => Replace Once rx Replacement ByteString where+    replace opt0@(Once opt1) p0 = vanilla_once $ rx' p0 opt1 -instance ReplaceCase_ GroupReplacer ByteString where-    replace_ = vanilla_replace+instance Regex_ rx => Replace All rx Replacement ByteString where+    replace opt0@(All opt1) p0 = vanilla_all $ rx' p0 opt1 -instance ReplaceCase_ GroupReplacer String where-    replace_  = vanilla_replace+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 -vanilla_replace::(O.ReplaceOpen [] r, O.ReplaceOpen Maybe r,-    Extract' a,Rx_ a a,Opt_ a) =>-        [ReplaceCase] -> Pattern Regex -> r a -> Body a -> a-vanilla_replace case0 p0 r0 b0 =-   let ma1 = marray_ p0 b0::Maybe MatchArray-       ma2 = marray_ p0 b0:: [MatchArray]-       isAll1 = All ` P.elem ` case0-   in if isAll1 then O.replace ma2 r0 b0-              else O.replace ma1 r0 b0+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 -addOpt::Opt_ a =>-    Pattern a -> [O.Comp] -> Pattern Regex-addOpt pat0 opt0 = Pattern rx1-    where rx1 = M.makeRegexOpts opt0 [] pat0 +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 -comp::[ReplaceCase]-> [O.Comp]-comp = P.map mapFn . P.filter filterFn-   where filterFn o1 = o1 `P.elem` [Utf8,Multiline]-         mapFn Utf8 = O.Utf8-         mapFn Multiline = O.Multiline++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/Trim.hs view
@@ -5,7 +5,9 @@ import qualified Data.ByteString as B import Text.Regex.Do.Convert import Text.Regex.Do.Pcre.Replace+import Text.Regex.Do.Type.MatchHint + {- | removes leading and trailing spaces and tabs   -}  class Trim a where@@ -13,7 +15,7 @@   instance Trim B.ByteString where-    trim bs1 = replace [All] rx1 repl1 $ Body bs1+    trim bs1 = replace (All []) rx1 repl1 $ Body bs1        where repl1 = Replacement B.empty              rx1 = rxFn "(^[\\s\\t]+)|([\\s\\t]+$)"              rxFn = Pattern . toByteString
src/Text/Regex/Do/Type/Do.hs view
@@ -1,7 +1,6 @@ module Text.Regex.Do.Type.Do where  import Text.Regex.Base.RegexLike as R-import Text.Regex.Do.Type.Reexport   -- | see "Text.Regex.Do.Pcre.ReplaceOpen" 'defaultReplacer' for example implementation@@ -24,12 +23,3 @@  -- | Offset, Length type PosLen = (MatchOffset, MatchLength)---data ReplaceCase = Once     -- ^ may be omitted-                | All       -- ^ if both Once and All are passed, All prevails-                | Utf8-                | Multiline deriving Eq---type Opt_ a = R.RegexMaker Regex CompOption ExecOption a
src/Text/Regex/Do/Type/Regex_.hs view
@@ -1,22 +1,40 @@ module Text.Regex.Do.Type.Regex_ where -import Text.Regex.Base.RegexLike as R+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/TestRegex/TestReplace.hs view
@@ -9,7 +9,8 @@ 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  main::IO() main = do@@ -23,19 +24,19 @@ doc = hspec $ do        describe "Pcre.Replace doc" $ do           it "replaceGroup 1" $ do-            replace [Once,Utf8] (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,Utf8] (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 "менее менее")+            replace (Once [Utf8]) (Pattern "менее") (Replacement  "более") (Body "менее менее")                 `shouldBe` "более менее"           it "replace 4" $ do-            replace [All,Utf8] (Pattern "менее") (Replacement  "боле") (Body "менее менее")+            replace (All[Utf8]) (Pattern "менее") (Replacement  "боле") (Body "менее менее")                 `shouldBe` "боле боле"           it "replace 5" $ do-            replace [Once,Utf8] (Pattern "^a\\s") (Replacement "A") (Body "a bc хол.гор.")+            replace (Once[]) (Pattern "^a\\s") (Replacement "A") (Body "a bc хол.гор.")                 `shouldBe` "Abc хол.гор."  @@ -43,24 +44,24 @@ onceUtf8 = hspec $ do        describe "Pcre.Replace Once Utf8" $ do           it "^a\\s" $ do-            replace [Once,Utf8] (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,Utf8] (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() latinOnceAll =  hspec $ do          describe "Pcre.Replace" $ do             it "Once" $ do-               runFn [Once] `shouldBe` toByteString "a=text1 b=11 12"+               runFn1 Once `shouldBe` toByteString "a=text1 b=11 12"             it "All" $ do-               runFn [All] `shouldBe` toByteString "a=text1 b=text1 12"-            where runFn opts =+               runFn1 All `shouldBe` toByteString "a=text1 b=text1 12"+            where runFn1 hint1 =                      let   rx1 = pattern "(?<==)(\\d{2})"                            body1 = Body $ toByteString haystack1                            haystack1 = "a=10 b=11 12"                            repl1  = replacement "text1"-                     in replace opts rx1 repl1 body1+                     in replace (hint1 []) rx1 repl1 body1   pattern::String -> Pattern ByteString@@ -75,9 +76,9 @@ groupReplace =  hspec $ do          describe "Pcre.Replace group" $ do             it "Once" $ do-               runFn1 [Once,Utf8] `shouldBe` "a=[сто один] b=3 12"+               runFn1 (Once[Utf8]) `shouldBe` "a=[сто один] b=3 12"             it "All" $ do-               runFn1 [All,Utf8] `shouldBe` "a=[сто один] b=[three] 12"+               runFn1 (All[Utf8]) `shouldBe` "a=[сто один] b=[three] 12"             where runFn1 opts1 =                      let   rx1 = Pattern "\\w=(\\d{1,3})"                            body1 = Body "a=101 b=3 12"