regex-base 0.83 → 0.90
raw patch · 4 files changed
+253/−80 lines, 4 files
Files
- Text/Regex/Base.hs +1/−1
- Text/Regex/Base/Context.hs +241/−78
- Text/Regex/Base/RegexLike.hs +10/−0
- regex-base.cabal +1/−1
Text/Regex/Base.hs view
@@ -53,6 +53,6 @@ getVersion_Text_Regex_Base :: Version getVersion_Text_Regex_Base =- Version { versionBranch = [0,83]+ Version { versionBranch = [0,90] , versionTags = ["unstable"] }
Text/Regex/Base/Context.hs view
@@ -9,88 +9,190 @@ Stability : experimental Portability : non-portable (MPTC+FD) -This is a module of instances of 'RegexContext'. Nothing else is-exported. These work for all the front ends and backends-interchangably. These instances are important because they provide-the different results that can be gotten from a match or matchM-operation (often via the @=~@ and @=~~@ operators). The name is Context-because they are context dependent: use them in a context that expects-an Int and you get a count of matches, use them in a Bool context and-get True if there is a match, etc.+This is a module of instances of 'RegexContext' (defined in+Text.Regex.Base.RegexLike). Nothing else is exported. This is+usually imported via the Text.Regex.Base convenience package which+itself is re-exported from newer Text.Regex.XXX modules provided by+the different regex-xxx backends. +These instances work for all the supported types and backends+interchangably. These instances provide the different results that+can be gotten from a match or matchM operation (often via the @=~@ and+@=~~@ operators with combine @makeRegex@ with @match@ and @matchM@+respectively). This module name is Context because they operators are+context dependent: use them in a context that expects an Int and you+get a count of matches, use them in a Bool context and get True if+there is a match, etc.++@RegexContext a b c@ takes a regular expression suppied in a type 'a'+generated by 'RegexMaker' and a target text supplied in type 'b' to a+result type 'c' using the 'match' class function. The 'matchM' class+function works like 'match' unless there is no match found, in which+case it calls 'fail' in the (arbitrary) monad context.++There are a few type synonyms from RegexLike that are used here:+ @ +-- | 0 based index from start of source, or (-1) for unused+type MatchOffset = Int+-- | non-negative length of a match+type MatchLength = Int type MatchArray = Array Int (MatchOffset, MatchLength) type MatchText source = Array Int (source, (MatchOffset, MatchLength)) @ -These are for the first match:+There are also a few newtypes that used to prevent any possible+overlap of types, which were not needed for GHC's late overlap+detection but are needed for use in Hugs. -(@ RegexLike a b => RegexContext a b Bool @) :- Whether there is any match or not+@+newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}+newtype AllTextSubmatches f b = AllTextSubmatches (f b)+newtype AllMatches f b = AllMatches (f b)+newtype AllTextMatches f b = AllTextMatches (f b)+@ -(@ RegexLike a b => RegexContext a b () @) :- Useful using @=~~@ in a monad, since failure to match is via 'fail'+The newtypes' @f@ parameters are the containers, usually @[]@ or+@Array Int@, (where the arrays all have lower bound 0). -(@ RegexLike a b => RegexContext a b (MatchOffset,MatchLength) @) :- This returns the initial index and length of the whole match.- Starting at (-1) indicates failure to match.+The two *Submatches newtypes return only information on the first+match. The other two newtypes return information on all the+non-overlapping matches. The two *Text* newtypes are used to mark+result types that contain the same type as the target text. -(@ RegexLike a b => RegexContext a b b @) :+Where provided, noncaptured submatches will have a @MatchOffset@ of+(-1) and non-negative otherwise. The semantics of submatches depend+on the backend and its compile and execution options. Where provided,+@MatchLength@ will always be non-negative. Arrays with no elements+are returned with bounds of (1,0). Arrays with elements will have a+lower bound of 0.++XXX THIS HADDOCK DOCUMENTATION IS OUT OF DATE XXX++These are for finding the first match in the target text:+++@ RegexContext a b Bool @ :+ Whether there is any match or not.+++@ RegexContext a b () @ :+ Useful as a guard with @matchM@ or @=~~@ in a monad, since failure to match calls 'fail'.+++@ RegexContext a b b @ : This returns the text of the whole match.- It will return 'empty' from 'Extract' if there is no match.- These are defined in other modules, but documented here for convenience.+ It will return 'empty' from the 'Extract' type class if there is no match.+ These are defined in each backend module, but documented here for convenience. -(@ RegexLike a b => RegexContext a b MatchArray @) :- Where each sub-part the match starts and its length.- Starting at (-1) indicates unused. -(@ RegexLike a b => RegexContext a b (Array Int b) @) :- The text of each sub-part of the match.- Unused matches are 'empty' (defined via 'Extract')+@ RegexContext a b (MatchOffset,MatchLength) @ :+ This returns the initial index and length of the whole match.+ MatchLength will always be non-negative, and 0 for a failed match. -(@ RegexLike a b => RegexContext a b (b, MatchText b, b) @) :- The text before the match, the details of the match, and the text after the match -(@ RegexLike a b => RegexContext a b (b, b, b) @) :+@ RegexContext a b (MatchResult b) @ : The+ 'MatchResult' structure with details for the match. This is the+ structure copied from the old @JRegex@ pacakge.+++@ RegexContext a b (b, b, b) @ : The text before the match, the text of the match, the text after the match -(@ RegexLike a b => RegexContext a b (b, b, b, [b]) @) :- The text before the match, the text of the match, the text after the match, and the text of the 1st and higher sub-parts of the match. This is the same return value as used in Text.Regex. -(@ RegexLike a b => RegexContext a b (MatchResult b) @) :- The 'MatchResult' structure for the match.+@ RegexContext a b (b, MatchText b, b) @ :+ The text before the match, the details of the match, and the text after the match -These instances are for all the matches (non-overlapping). Note that backends are supposed to supply RegexLike instances for which matchAll and matchAllText stop searching after returning any successful but empty match. -(@ RegexLike a b => RegexContext a b Int @) :- The number of matches+@ RegexContext a b (b, b, b, [b]) @ : + The text before the match, the text of the match, the text after the+ match, and a list of the text of the 1st and higher sub-parts of the+ match. This is the same return value as used in the old+ @Text.Regex@ API. -These instances similar to the single match ones above, but in a List:+Two containers of the submatch offset information: -(@ RegexLike a b => RegexContext a b [(MatchOffset, MatchLength)] @) : -(@ RegexLike a b => RegexContext a b [b] @) :- As a policy, I chose [b] to be the list of whole text of each match.+@ RegexContext a b MatchArray @ :+ Array of @(MatchOffset,MatchLength)@ for all the sub matches.+ The whole match is at the intial 0th index.+ Noncaptured submatches will have a @MatchOffset@ of (-1)+ The array will have no elements and bounds (1,0) if there is no match. -(@ RegexLike a b => RegexContext a b [MatchArray] @) : -(@ RegexLike a b => RegexContext a b [Array Int b] @) :+@ RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength) @ :+ List of @(MatchOffset,MatchLength)@+ The whole match is the first element, the rest are the submatches (if any) in order.+ The list is empty if there is no match. -(@ RegexLike a b => RegexContext a b [MatchText b] @) :+Two containers of the submatch text and offset information: -(@ RegexLike a b => RegexContext a b [[b]] @) :- This is the list of the list of the text of the sub-part of each match.- Unused matches are 'empty' (defined via 'Extract')+@ RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) @ +@ RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength))) @++Two containers of the submatch text information:++@ RegexContext a b (AllTextSubmatches [] b) @++@ RegexContext a b (AllTextSubmatches (Array Int) b) @++These instances are for all the matches (non-overlapping). Note that+backends are supposed to supply 'RegexLike' instances for which the+default 'matchAll' and 'matchAllText' stop searching after returning+any successful but empty match.+++@ RegexContext a b Int @ :+ The number of matches, non-negative.++Two containers for locations of all matches:++@ RegexContext a b (AllMatches [] (MatchOffset, MatchLength)) @++@ RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) @++Two containers for the locations of all matches and their submatches:++@ RegexContext a b [MatchArray] @ :++@ RegexContext a b (AllMatches (Array Int) MatchArray) @++Two containers for the text and locations of all matches and their submatches:++@ RegexContext a b [MatchText b] @++@ RegexContext a b (AllTextMatches (Array Int) (MatchText b)) @++Two containers for text of all matches:+@ RegexContext a b (AllTextMatches [] b) @++@ RegexContext a b (AllTextMatches (Array Int) b) @++Four containers for text of all matches and their submatches:++@ RegexContext a b [[b]] @++@ RegexContext a b (AllTextMatches (Array Int) [b]) @++@ RegexContext a b (AllTextMatches [] (Array Int b)) @++@ RegexContext a b (AllTextMatches (Array Int) (Array Int b)) @++Unused matches are 'empty' (defined via 'Extract')+ -} module Text.Regex.Base.Context() where +import Control.Monad(liftM) import Data.Array(Array,(!),elems,listArray) import Data.Maybe(maybe) import Text.Regex.Base.RegexLike(RegexLike(..),RegexContext(..)+ ,AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..) ,MatchResult(..),Extract(empty),MatchOffset,MatchLength,MatchArray,MatchText) + {- -- Get the ByteString type for mood/doom import Data.ByteString(ByteString)@@ -141,12 +243,24 @@ {-# INLINE nullArray #-} nullArray = listArray (1,0) [] -nullFail :: (RegexContext regex source [target],Monad m) => regex -> source -> m [target]+nullFail :: (RegexContext regex source (AllMatches [] target),Monad m) => regex -> source -> m (AllMatches [] target) {-# INLINE nullFail #-} nullFail r s = case match r s of- [] -> regexFailed+ (AllMatches []) -> regexFailed xs -> return xs +nullFailText :: (RegexContext regex source (AllTextMatches [] target),Monad m) => regex -> source -> m (AllTextMatches [] target)+{-# INLINE nullFailText #-}+nullFailText r s = case match r s of+ (AllTextMatches []) -> regexFailed+ xs -> return xs++nullFail' :: (RegexContext regex source ([] target),Monad m) => regex -> source -> m ([] target)+{-# INLINE nullFail' #-}+nullFail' r s = case match r s of+ ([]) -> regexFailed+ xs -> return xs+ regexFailed :: (Monad m) => m b {-# INLINE regexFailed #-} regexFailed = fail $ "regex failed to match"@@ -185,18 +299,21 @@ match r s = maybe (-1,0) (!0) (matchOnce r s) matchM r s = maybe regexFailed (return.(!0)) (matchOnce r s) -instance (RegexLike a b) => RegexContext a b MatchArray where - match r s = maybe nullArray id (matchOnce r s)- matchM r s = maybe regexFailed return (matchOnce r s)+instance (RegexLike a b) => RegexContext a b (MatchResult b) where + match r s = maybe (MR {mrBefore = s,mrMatch = empty,mrAfter = empty+ ,mrSubs = nullArray,mrSubList = []}) id (matchM r s)+ matchM = actOn (\(pre,ma,post) -> + let ((whole,_):subs) = elems ma+ in MR { mrBefore = pre+ , mrMatch = whole+ , mrAfter = post+ , mrSubs = fmap fst ma+ , mrSubList = map fst subs }) instance (RegexLike a b) => RegexContext a b (b,MatchText b,b) where match r s = maybe (s,nullArray,empty) id (matchOnceText r s) matchM r s = maybe regexFailed return (matchOnceText r s) -instance (RegexLike a b) => RegexContext a b (Array Int b) where - match r s = maybe nullArray id (matchM r s)- matchM = actOn (\(_,ma,_) -> fmap fst ma)- instance (RegexLike a b) => RegexContext a b (b,b,b) where match r s = maybe (s,empty,empty) id (matchM r s) matchM = actOn (\(pre,ma,post) -> let ((whole,_):_) = elems ma@@ -207,39 +324,85 @@ matchM = actOn (\(pre,ma,post) -> let ((whole,_):subs) = elems ma in (pre,whole,post,map fst subs)) -instance (RegexLike a b) => RegexContext a b (MatchResult b) where - match r s = maybe (MR {mrBefore = s,mrMatch = empty,mrAfter = empty- ,mrSubs = nullArray,mrSubList = []}) id (matchM r s)- matchM = actOn (\(pre,ma,post) -> - let ((whole,_):subs) = elems ma- in MR { mrBefore = pre- , mrMatch = whole- , mrAfter = post- , mrSubs = fmap fst ma- , mrSubList = map fst subs })+-- now AllSubmatches wrapper+instance (RegexLike a b) => RegexContext a b MatchArray where + match r s = maybe nullArray id (matchOnce r s)+ matchM r s = maybe regexFailed return (matchOnce r s)+instance (RegexLike a b) => RegexContext a b (AllSubmatches [] (MatchOffset,MatchLength)) where + match r s = maybe (AllSubmatches []) id (matchM r s)+ matchM r s = case matchOnce r s of+ Nothing -> regexFailed+ Just ma -> return (AllSubmatches (elems ma)) +-- essentially AllSubmatches applied to (MatchText b)+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) (b, (MatchOffset, MatchLength))) where + match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)+ matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches ma) r s+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] (b, (MatchOffset, MatchLength))) where + match r s = maybe (AllTextSubmatches []) id (matchM r s)+ matchM r s = actOn (\(_,ma,_) -> AllTextSubmatches (elems ma)) r s++instance (RegexLike a b) => RegexContext a b (AllTextSubmatches [] b) where + match r s = maybe (AllTextSubmatches []) id (matchM r s)+ matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> map fst . elems $ ma) r s+instance (RegexLike a b) => RegexContext a b (AllTextSubmatches (Array Int) b) where + match r s = maybe (AllTextSubmatches nullArray) id (matchM r s)+ matchM r s = liftM AllTextSubmatches $ actOn (\(_,ma,_) -> fmap fst ma) r s+ -- ** Instances based on matchAll,matchAllText +instance (RegexLike a b) => RegexContext a b (AllMatches [] (MatchOffset,MatchLength)) where+ match r s = AllMatches [ ma!0 | ma <- matchAll r s ]+ matchM r s = nullFail r s+instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) (MatchOffset,MatchLength)) where+ match r s = maybe (AllMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ (AllMatches []) -> regexFailed+ (AllMatches pairs) -> return . AllMatches . listArray (0,pred $ length pairs) $ pairs++-- No AllMatches wrapper instance (RegexLike a b) => RegexContext a b [MatchArray] where match = matchAll- matchM = nullFail+ matchM = nullFail'+instance (RegexLike a b) => RegexContext a b (AllMatches (Array Int) MatchArray) where+ match r s = maybe (AllMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ [] -> regexFailed+ mas -> return . AllMatches . listArray (0,pred $ length mas) $ mas +-- No AllTextMatches wrapper instance (RegexLike a b) => RegexContext a b [MatchText b] where match = matchAllText- matchM = nullFail- -instance (RegexLike a b) => RegexContext a b [(MatchOffset,MatchLength)] where- match r s = [ ma!0 | ma <- matchAll r s ]- matchM = nullFail--instance (RegexLike a b) => RegexContext a b [b] where- match r s = [ fst (ma!0) | ma <- matchAllText r s ]- matchM = nullFail+ matchM = nullFail'+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (MatchText b)) where+ match r s = maybe (AllTextMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ ([]) -> regexFailed+ (mts) -> return . AllTextMatches . listArray (0,pred $ length mts) $ mts -instance (RegexLike a b) => RegexContext a b [Array Int b] where- match r s = [ fmap fst ma | ma <- matchAllText r s ]- matchM = nullFail+instance (RegexLike a b) => RegexContext a b (AllTextMatches [] b) where+ match r s = AllTextMatches [ fst (ma!0) | ma <- matchAllText r s ]+ matchM r s = nullFailText r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) b) where+ match r s = maybe (AllTextMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ (AllTextMatches []) -> regexFailed+ (AllTextMatches bs) -> return . AllTextMatches . listArray (0,pred $ length bs) $ bs +-- No AllTextMatches wrapper instance (RegexLike a b) => RegexContext a b [[b]] where match r s = [ map fst (elems ma) | ma <- matchAllText r s ]- matchM = nullFail+ matchM r s = nullFail' r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) [b]) where+ match r s = maybe (AllTextMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ ([]) -> regexFailed+ (ls) -> return . AllTextMatches . listArray (0,pred $ length ls) $ ls+instance (RegexLike a b) => RegexContext a b (AllTextMatches [] (Array Int b)) where+ match r s = AllTextMatches [ fmap fst ma | ma <- matchAllText r s ]+ matchM r s = nullFailText r s+instance (RegexLike a b) => RegexContext a b (AllTextMatches (Array Int) (Array Int b)) where+ match r s = maybe (AllTextMatches nullArray) id (matchM r s)+ matchM r s = case match r s of+ (AllTextMatches []) -> regexFailed+ (AllTextMatches as) -> return . AllTextMatches . listArray (0,pred $ length as) $ as
Text/Regex/Base/RegexLike.hs view
@@ -36,6 +36,7 @@ RegexLike(..), RegexContext(..), Extract(..),+ AllSubmatches(..),AllTextSubmatches(..),AllMatches(..),AllTextMatches(..) ) where import Control.Monad.Error()@@ -217,3 +218,12 @@ instance Extract (S.Seq a) where before = S.take; after = S.drop; empty = S.empty++-- | Used in results of RegexContext instances+newtype AllSubmatches f b = AllSubmatches {getAllSubmatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllTextSubmatches f b = AllTextSubmatches {getAllTextSubmatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllMatches f b = AllMatches {getAllMatches :: (f b)}+-- | Used in results of RegexContext instances+newtype AllTextMatches f b = AllTextMatches {getAllTextMatches :: (f b) }
regex-base.cabal view
@@ -1,5 +1,5 @@ Name: regex-base-Version: 0.83+Version: 0.90 -- Cabal-Version: >=1.1.4 License: BSD3 License-File: LICENSE