regex-do 2.4 → 2.5
raw patch · 29 files changed
+930/−550 lines, 29 files
Files
- changelog.md +6/−0
- regex-do.cabal +16/−8
- src/Text/Regex/Do/Convert.hs +3/−0
- src/Text/Regex/Do/Pcre/Ascii/Match.hs +69/−0
- src/Text/Regex/Do/Pcre/Ascii/MatchHint.hs +85/−0
- src/Text/Regex/Do/Pcre/Ascii/Replace.hs +79/−0
- src/Text/Regex/Do/Pcre/Match.hs +0/−72
- src/Text/Regex/Do/Pcre/MatchHint.hs +0/−82
- src/Text/Regex/Do/Pcre/Matchf.hs +28/−16
- src/Text/Regex/Do/Pcre/Replace.hs +0/−127
- src/Text/Regex/Do/Pcre/ReplaceOpen.hs +0/−144
- src/Text/Regex/Do/Pcre/Result.hs +0/−22
- src/Text/Regex/Do/Pcre/Utf8/Match.hs +80/−0
- src/Text/Regex/Do/Pcre/Utf8/MatchHint.hs +75/−0
- src/Text/Regex/Do/Pcre/Utf8/Replace.hs +83/−0
- src/Text/Regex/Do/ReplaceOpen.hs +143/−0
- src/Text/Regex/Do/Result.hs +22/−0
- src/Text/Regex/Do/Trim.hs +8/−4
- src/Text/Regex/Do/Type/Do.hs +47/−1
- src/Text/Regex/Do/Type/Extract.hs +15/−2
- src/Text/Regex/Do/Type/MatchHint.hs +35/−6
- src/Text/Regex/Do/Type/Regex.hs +60/−0
- src/Text/Regex/Do/Type/Regex_.hs +0/−40
- test/Main.hs +3/−2
- test/TestRegex/TestPcre.hs +18/−2
- test/TestRegex/TestReplace.hs +15/−14
- test/TestRegex/TestReplaceOpen.hs +1/−1
- test/TestRegex/TestReplaceUtf.hs +31/−0
- test/TestRegex/TestSplit.hs +8/−7
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 ":"