packages feed

pcre-utils (empty) → 0.1.0.0

raw patch · 6 files changed

+276/−0 lines, 6 filesdep +HUnitdep +attoparsecdep +basesetup-changed

Dependencies added: HUnit, attoparsec, base, bytestring, mtl, pcre-utils, regex-pcre-builtin, vector

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Simon Marechal++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Simon Marechal nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Text/Regex/PCRE/ByteString/Utils.hs view
@@ -0,0 +1,129 @@+module Text.Regex.PCRE.ByteString.Utils+    ( substitute+    , split+    , substituteCompile+    , splitCompile+    ) where++import Text.Regex.PCRE.ByteString+import qualified Data.ByteString.Char8 as BS+import Control.Monad.Error+import qualified Data.Vector as V+import Data.Attoparsec.ByteString.Char8+import Control.Applicative++{-| Substitutes values matched by a `Regex`. References can be used.++It doesn't support anything else than global substitution for now ..+-}+substitute :: Regex             -- ^ The regular expression, taken from a call to `compile`+           -> BS.ByteString     -- ^ The source string+           -> BS.ByteString     -- ^ The replacement string+           -> IO (Either String BS.ByteString)+substitute regexp srcstring repla = runErrorT $ do+    let check x = case x of+                      Right y -> return y+                      Left rr -> throwError rr+    parsedReplacement <- check (parseOnly repparser repla)+    (matches, captures) <- getMatches regexp srcstring V.empty+    let !replaceString = applyCaptures parsedReplacement captures+        applyReplacement :: RegexpSplit BS.ByteString -> BS.ByteString+        applyReplacement (Unmatched x) = x+        applyReplacement (Matched _) = replaceString+    return $! BS.concat $! map applyReplacement matches++-- Transforms the parsed replacement and the vector of captured stuff into+-- the destination ByteString.+applyCaptures :: [Replacement] -> V.Vector BS.ByteString -> BS.ByteString+applyCaptures repl capt = BS.concat (map applyCaptures' repl)+    where+        applyCaptures' :: Replacement -> BS.ByteString+        applyCaptures' (RawReplacement r) = r+        applyCaptures' (IndexedReplacement idx) = if V.length capt < idx+                                                      then ""+                                                      else capt V.! (idx-1)++-- | Splits strings, using a `Regex` as delimiter.+split :: Regex  -- ^ The regular expression, taken from a call to `compile`+      -> BS.ByteString -- ^ The source string+      -> IO (Either String [BS.ByteString])+split regexp srcstring = fmap (either Left (Right . removeEmptyLeft . regexpUnmatched . fst)) $ runErrorT (getMatches regexp srcstring V.empty)+    where+        removeEmptyLeft = reverse . dropWhile BS.null . reverse++data RegexpSplit a = Matched a+                   | Unmatched a+                   deriving (Show, Eq, Ord)++instance Functor RegexpSplit where+    fmap f (Matched x)   = Matched (f x)+    fmap f (Unmatched x) = Unmatched (f x)++regexpAll :: [RegexpSplit a] -> [a]+regexpAll = map unreg+    where+        unreg ( Matched x   ) = x+        unreg ( Unmatched x ) = x++isMatched :: RegexpSplit a -> Bool+isMatched (Matched _) = True+isMatched _ = False++regexpUnmatched :: [RegexpSplit a] -> [a]+regexpUnmatched = regexpAll . filter (not . isMatched)++getMatches :: Regex -> BS.ByteString -> V.Vector BS.ByteString -> ErrorT String IO ([RegexpSplit BS.ByteString], V.Vector BS.ByteString)+getMatches _ "" curcaptures  = return ([], curcaptures)+getMatches creg src curcaptures = do+    x <- liftIO $ regexec creg src+    case x of+        Left (rcode, rerror) -> throwError ("Regexp application error: " ++ rerror ++ "(" ++ show rcode ++ ")")+        Right Nothing -> return ([Unmatched src], curcaptures)++        -- Now this is a trick, I don't know exactly why this happens, but this happens with empty regexps. We are going to cheat here+        Right (Just ("","",rm,_)) -> return (map (Unmatched . BS.singleton) (BS.unpack rm), curcaptures)++        Right (Just (before,current,remaining,captures)) -> do+            (remain, nextcaptures) <- getMatches creg remaining (curcaptures V.++ (V.fromList captures))+            return (Unmatched before : Matched current : remain, nextcaptures)+++data Replacement = RawReplacement BS.ByteString+                 | IndexedReplacement Int+                 deriving (Show)++repparser :: Parser [Replacement]+repparser = many replacement <* endOfInput++replacement :: Parser Replacement+replacement = fmap RawReplacement rawData <|> escapedThing++rawData :: Parser BS.ByteString+rawData = takeWhile1 (/= '\\')++escapedThing :: Parser Replacement+escapedThing = do+    void (char '\\')+    fmap IndexedReplacement decimal <|> fmap (RawReplacement . BS.cons '\\') rawData+++-- | Compiles the regular expression (using default options) and `substitute`s+substituteCompile :: BS.ByteString     -- ^ The regular expression+                  -> BS.ByteString     -- ^ The source string+                  -> BS.ByteString     -- ^ The replacement string+                  -> IO (Either String BS.ByteString)+substituteCompile regexp srcstring repla = do+    re <- compile compBlank execBlank regexp+    case re of+        Right cre -> substitute cre srcstring repla+        Left rr   -> return $ Left $ "Regexp compilation failed: " ++ show rr++-- | Compiles the regular expression (using default options) and `split`s.+splitCompile :: BS.ByteString -- ^ The regular expression+             -> BS.ByteString -- ^ The source string+             -> IO (Either String [BS.ByteString])+splitCompile regexp srcstring = do+    re <- compile compBlank execBlank regexp+    case re of+        Right cre -> split cre srcstring+        Left rr   -> return $ Left $ "Regexp compilation failed: " ++ show rr
+ pcre-utils.cabal view
@@ -0,0 +1,45 @@+-- Initial pcre-utils.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                pcre-utils+version:             0.1.0.0+synopsis:            Perl-like substitute and split for PCRE regexps.+description:         This package introduces split and replace like functions using PCRE regexps.+license:             BSD3+license-file:        LICENSE+author:              Simon Marechal+maintainer:          bartavelle@gmail.com+-- copyright:           +category:            Text+build-type:          Simple+cabal-version:       >=1.8++source-repository head+  type: git+  location: git://github.com/bartavelle/pcre-utils.git+++library+  exposed-modules:     Text.Regex.PCRE.ByteString.Utils+  -- other-modules:       +  ghc-options:         -Wall+  ghc-prof-options:    -caf-all -auto-all+  extensions:          OverloadedStrings, BangPatterns+  build-depends:       base ==4.6.*, regex-pcre-builtin, bytestring, attoparsec, mtl, vector++Test-Suite test-split+    hs-source-dirs: test+    type:           exitcode-stdio-1.0+    ghc-options:    -Wall+    extensions:     OverloadedStrings+    build-depends:  base,pcre-utils,HUnit,bytestring, regex-pcre-builtin+    main-is:        split.hs++Test-Suite test-subs+    hs-source-dirs: test+    type:           exitcode-stdio-1.0+    ghc-options:    -Wall+    extensions:     OverloadedStrings+    build-depends:  base,pcre-utils,HUnit,bytestring, regex-pcre-builtin+    main-is:        subs.hs+
+ test/split.hs view
@@ -0,0 +1,39 @@+module Main where++import Test.HUnit+import Text.Regex.PCRE.ByteString+import Text.Regex.PCRE.ByteString.Utils+import qualified Data.ByteString as BS++tests :: [(BS.ByteString, BS.ByteString, [BS.ByteString])]+tests = [ ("a"   , "lala"       , ["l","l"])+        , ("l"   , "lala"       , ["", "a", "a"])+        , ("x"   , "lala"       , ["lala"])+        , ("[la]", "lalaz"      , ["", "", "", "", "z"])+        , ("[la]", "lalazoula"  , ["", "", "", "", "zou"])+        , ("[la]", "lalazoulaz" , ["", "", "", "", "zou", "", "z"])+        , ("[la]", "lala"       , [])+        , ("l"   , "l\nl"       , ["", "\n"])+        , (""    , "abc"        , ["a", "b", "c"])+        , ("(ha)", "lahachac"      , ["la","c","c"])+        ]++toTest :: (BS.ByteString, BS.ByteString, [BS.ByteString]) -> IO Test+toTest cas@(regexp, string, result) = do+    let failtest :: String -> IO Test+        failtest rr = return $ TestCase $ assertFailure $ rr ++ " " ++ show cas+    x <- compile compBlank execBlank regexp+    case x of+        Left  rr -> failtest ("Failure when compiling regexp: " ++ show rr)+        Right rregexp -> do+            res <- split rregexp string+            case res of+                Right rs -> return (rs ~?= result)+                Left err -> failtest ("Could not split regexp: " ++ err)++main :: IO ()+main = do+    (Counts _ _ e f) <- fmap TestList (mapM toTest tests) >>= runTestTT+    if (e > 0) || (f > 0)+        then error "Tests failed"+        else return ()
+ test/subs.hs view
@@ -0,0 +1,31 @@+module Main where++import Test.HUnit+import Text.Regex.PCRE.ByteString+import Text.Regex.PCRE.ByteString.Utils+import qualified Data.ByteString as BS++tests :: [(BS.ByteString, BS.ByteString, BS.ByteString, BS.ByteString)]+tests = [ ("l", "x", "lap\\nin", "xap\\nin")+        , ("log(\\d+)truc", "x\\1x", "log186truc", "x186x")+        ]++toTest :: (BS.ByteString, BS.ByteString, BS.ByteString, BS.ByteString) -> IO Test+toTest cas@(regexp, replacement, string, result) = do+    let failtest :: String -> IO Test+        failtest rr = return $ TestCase $ assertFailure $ rr ++ " " ++ show cas+    x <- compile compBlank execBlank regexp+    case x of+        Left  rr -> failtest ("Failure when compiling regexp: " ++ show rr)+        Right rregexp -> do+            res <- substitute rregexp string replacement+            case res of+                Right rs -> return (rs ~?= result)+                Left err -> failtest ("Could not split regexp: " ++ err)++main :: IO ()+main = do+    (Counts _ _ e f) <- fmap TestList (mapM toTest tests) >>= runTestTT+    if (e > 0) || (f > 0)+        then error "Tests failed"+        else return ()