packages feed

pcre-heavy 0.1.0 → 0.2.0

raw patch · 3 files changed

+87/−58 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Text.Regex.PCRE.Heavy: instance [overlap ok] RegexResult (Maybe [ByteString])
- Text.Regex.PCRE.Heavy: instance [overlap ok] RegexResult Bool
- Text.Regex.PCRE.Heavy: instance [overlap ok] Stringable a => RegexResult (Maybe [a])
+ Text.Regex.PCRE.Heavy: compileM :: ByteString -> [PCREOption] -> Either String Regex
+ Text.Regex.PCRE.Heavy: scanRanges :: Stringable a => Regex -> a -> [((Int, Int), [(Int, Int)])]
+ Text.Regex.PCRE.Heavy: scanRangesO :: Stringable a => Regex -> [PCREExecOption] -> a -> [((Int, Int), [(Int, Int)])]
- Text.Regex.PCRE.Heavy: (=~) :: (Stringable a, RegexResult b) => a -> Regex -> b
+ Text.Regex.PCRE.Heavy: (=~) :: Stringable a => a -> Regex -> Bool
- Text.Regex.PCRE.Heavy: scan :: Stringable a => Regex -> a -> [[a]]
+ Text.Regex.PCRE.Heavy: scan :: Stringable a => Regex -> a -> [(a, [a])]
- Text.Regex.PCRE.Heavy: scanO :: Stringable a => Regex -> [PCREExecOption] -> a -> [[a]]
+ Text.Regex.PCRE.Heavy: scanO :: Stringable a => Regex -> [PCREExecOption] -> a -> [(a, [a])]

Files

README.md view
@@ -18,36 +18,37 @@ import           Text.Regex.PCRE.Heavy ``` -### Matching+### Checking  ```haskell->>> "https://unrelenting.technology" =~ [re|^http.*|] :: Bool+>>> "https://unrelenting.technology" =~ [re|^http.*|] True ``` -In an `if`, you don't even need the annotation:+### Matching (Searching) -```haskell-if "https://unrelenting.technology" =~ [re|^http.*|] then "YEP" else "NOPE"-```+(You can use any string type, not just String!) -Extracting matches (You can use any string type, not just String)+`scan` returns all matches as pairs like `(fullmatch, [group, group...])`.  ```haskell->>> "https://unrelenting.technology" =~ [re|^https?://([^\.]+)\..*|] :: Maybe [String]-Just ["https://unrelenting.technology","unrelenting"]+>>> scan [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi" :: [(String, [String])]+[+  (" entry 1 hello  &", ["1", "hello"])+, ("entry 2 hi",        ["2", "hi"])+] ``` -`scan` returns all matches (search)+It is lazy!+If you only need the first match, use `head` (or, much better, `headMay` from [safe]) -- no extra work will be performed!  ```haskell->>> scan [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi" :: [[String]]-[-  [" entry 1 hello  &", "1", "hello"]-, ["entry 2 hi",        "2", "hi"]-]+>>> headMay $ scan [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi"+Just (" entry 1 hello  &", ["1", "hello"]) ``` +[safe]: https://hackage.haskell.org/package/safe+ ### Replacement  `sub` replaces the first match, `gsub` replaces all matches.@@ -69,6 +70,18 @@ -- That will get both the full match and the groups. -- I have no idea why you would want to use that, but that's there :-) ```++### Options++You can pass `pcre-light` options like this:++```haskell+>>> let myRe = mkRegexQQ [multiline, utf8, ungreedy]+>>> scanO [myRe|\s*entry (\d+) (\w+)\s*&?|] [exec_no_utf8_check] " entry 1 hello  &entry 2 hi" :: [[String]]+>>> gsubO [myRe|\d+|] [exec_notempty] "!!!NUMBER!!!" "Copyright (c) 2015 The 000 Group"+```++`utf8` is passed by default in the `re` QuasiQuoter.  ## License 
library/Text/Regex/PCRE/Heavy.hs view
@@ -10,6 +10,8 @@   (=~) , scan , scanO+, scanRanges+, scanRangesO   -- * Replacement , sub , subO@@ -18,9 +20,10 @@   -- * QuasiQuoter , re , mkRegexQQ-  -- * Types from pcre-light+  -- * Types and stuff from pcre-light , Regex , PCREOption+, PCRE.compileM   -- * Advanced raw stuff , rawMatch , rawSub@@ -33,43 +36,29 @@ import           Text.Regex.PCRE.Light.Base import           Control.Applicative ((<$>)) import           Data.Maybe (isJust, fromMaybe)+import           Data.List (unfoldr) import           Data.Stringable import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Internal as BS import           System.IO.Unsafe (unsafePerformIO) import           Foreign -class RegexResult a where-  fromResult :: Maybe [BS.ByteString] -> a--instance RegexResult (Maybe [BS.ByteString]) where-  fromResult = id--instance Stringable a => RegexResult (Maybe [a]) where-  fromResult x = map fromByteString <$> x+substr :: BS.ByteString -> (Int, Int) -> BS.ByteString+substr s (f, t) = BS.take (t - f) . BS.drop f $ s -instance RegexResult Bool where-  fromResult = isJust+behead :: [a] -> (a, [a])+behead (h:t) = (h, t)+behead [] = error "no head to behead" -reMatch :: (Stringable a, RegexResult b) => Regex -> a -> b-reMatch r s = fromResult $ PCRE.match r (toByteString s) []+reMatch :: Stringable a => Regex -> a -> Bool+reMatch r s = isJust $ PCRE.match r (toByteString s) [] --- | Matches a string with a regex.------ You can cast the result to Bool or Maybe [Stringable]--- Maybe [Stringable] only represents the first match and its groups.--- Use 'scan' to find all matches.------ Note: if casts to bool automatically.+-- | Checks whether a string matches a regex. -- -- >>> :set -XQuasiQuotes--- >>> "https://unrelenting.technology" =~ [re|^http.*|] :: Bool+-- >>> "https://unrelenting.technology" =~ [re|^http.*|] -- True--- >>> "https://unrelenting.technology" =~ [re|^https?://([^\.]+)\..*|] :: Maybe [String]--- Just ["https://unrelenting.technology","unrelenting"]--- >>> if "https://unrelenting.technology" =~ [re|^http.*|] then "YEP" else "NOPE"--- "YEP"-(=~) :: (Stringable a, RegexResult b) => a -> Regex -> b+(=~) :: Stringable a => a -> Regex -> Bool (=~) = flip reMatch  -- | Does raw PCRE matching (you probably shouldn't use this directly).@@ -102,26 +91,46 @@                   loop (n + 1) (o + 2) ((fromIntegral i, fromIntegral j) : acc)           in loop 0 0 [] -substr :: BS.ByteString -> (Int, Int) -> BS.ByteString-substr s (f, t) = BS.take (t - f) . BS.drop f $ s+nextMatch :: Regex -> [PCREExecOption] -> BS.ByteString -> Int -> Maybe ([(Int, Int)], Int)+nextMatch r opts str offset =+  case rawMatch r str offset opts of+    Nothing -> Nothing+    Just [] -> Nothing+    Just ms -> Just (ms, maximum $ map snd ms)  -- | Searches the string for all matches of a given regex. -- -- >>> scan [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi"--- [[" entry 1 hello  &","1","hello"],["entry 2 hi","2","hi"]]-scan :: (Stringable a) => Regex -> a -> [[a]]+-- [(" entry 1 hello  &",["1","hello"]),("entry 2 hi",["2","hi"])]+--+-- It is lazy! If you only need the first match, just apply 'head' (or+-- 'headMay' from the "safe" library) -- no extra work will be performed!+--+-- >>> head $ scan [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi"+-- (" entry 1 hello  &",["1","hello"])+scan :: (Stringable a) => Regex -> a -> [(a, [a])] scan r s = scanO r [] s  -- | Exactly like 'scan', but passes runtime options to PCRE.-scanO :: (Stringable a) => Regex -> [PCREExecOption] -> a -> [[a]]-scanO r opts s = map fromByteString <$> loop 0 []+scanO :: (Stringable a) => Regex -> [PCREExecOption] -> a -> [(a, [a])]+scanO r opts s = map behead $ map (fromByteString . substr str) <$> unfoldr (nextMatch r opts str) 0   where str = toByteString s-        loop offset acc =-          case rawMatch r str offset opts of-            Nothing -> reverse acc-            Just [] -> reverse acc-            Just ms -> loop (maximum $ map snd ms) ((map (substr str) ms) : acc) +-- | Searches the string for all matches of a given regex, like 'scan', but+-- returns positions inside of the string.+--+-- >>> scanRanges [re|\s*entry (\d+) (\w+)\s*&?|] " entry 1 hello  &entry 2 hi"+-- [((0,17),[(7,8),(9,14)]),((17,27),[(23,24),(25,27)])]+--+-- And just like 'scan', it's lazy.+scanRanges :: (Stringable a) => Regex -> a -> [((Int, Int), [(Int, Int)])]+scanRanges r s = scanRangesO r [] s++-- | Exactly like 'scanRanges', but passes runtime options to PCRE.+scanRangesO :: Stringable a => Regex -> [PCREExecOption] -> a -> [((Int, Int), [(Int, Int)])]+scanRangesO r opts s = map behead $ unfoldr (nextMatch r opts str) 0+  where str = toByteString s+ class RegexReplacement a where   performReplacement :: BS.ByteString -> [BS.ByteString] -> a -> BS.ByteString @@ -187,11 +196,12 @@             _ -> acc  instance Lift PCREOption where-  lift o = [| o |]+  -- well, the constructor isn't exported, but at least it implements Read/Show :D+  lift o = let o' = show o in [| read o' :: PCREOption |]  quoteExpRegex :: [PCREOption] -> String -> ExpQ-quoteExpRegex opts txt = [| PCRE.compile (BS.pack txt) opts |]-  where !_ = PCRE.compile (BS.pack txt) opts -- check at compile time+quoteExpRegex opts txt = [| PCRE.compile (toByteString (txt :: String)) opts |]+  where !_ = PCRE.compile (toByteString txt) opts -- check at compile time  -- | Returns a QuasiQuoter like 're', but with given PCRE options. mkRegexQQ :: [PCREOption] -> QuasiQuoter@@ -203,4 +213,4 @@  -- | A QuasiQuoter for regular expressions that does a compile time check. re :: QuasiQuoter-re = mkRegexQQ []+re = mkRegexQQ [utf8]
pcre-heavy.cabal view
@@ -1,7 +1,13 @@ name:            pcre-heavy-version:         0.1.0+version:         0.2.0 synopsis:        A regexp library on top of pcre-light you can actually use.-description:     https://github.com/myfreeweb/pcre-heavy+description:+    A regular expressions library that does not suck.++    - based on <https://hackage.haskell.org/package/pcre-light pcre-light>+    - takes and returns <https://hackage.haskell.org/package/stringable Stringables> everywhere+    - a QuasiQuoter for regexps that does compile time checking+    - SEARCHES FOR MULTIPLE MATCHES! DOES REPLACEMENT! category:        Web homepage:        https://github.com/myfreeweb/pcre-heavy author:          Greg V