diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Matthias Fischmann
+
+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 Matthias Fischmann 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.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Text/Regex/Easy.hs b/Text/Regex/Easy.hs
new file mode 100644
--- /dev/null
+++ b/Text/Regex/Easy.hs
@@ -0,0 +1,123 @@
+{-# LANGUAGE FlexibleContexts                         #-}
+{-# LANGUAGE GADTs                                    #-}
+{-# LANGUAGE MultiParamTypeClasses                    #-}
+{-# LANGUAGE NoImplicitPrelude                        #-}
+{-# LANGUAGE OverloadedStrings                        #-}
+{-# LANGUAGE ScopedTypeVariables                      #-}
+
+{-# OPTIONS -fwarn-unused-imports #-}
+
+-- | This module provides perl-style pattern matching.  It is intended
+-- for use with minimal Haskell knowledge, so it moves away from the
+-- complex regex-* type signatures for the sake of clarity, and always
+-- uses the same string types for source text and patterns.  See
+-- 'tests' in source code for a few examples.
+module Text.Regex.Easy
+  ( module Text.Regex.PCRE
+  , Match, Source
+  , (=~+)
+  , (=~-)
+  , (=~#)
+  , (=~++)
+  , replaceRegex
+  , replaceRegexAll
+  )
+where
+
+import Data.Array as AR
+import Data.Function
+import Data.List as List
+import Data.Monoid
+import Data.String.Conversions
+import Prelude hiding ((++))
+import Text.Regex.PCRE
+
+import qualified Data.ByteString.Lazy as LBS
+
+
+-- | Rudimentary tests.  Read the source as a form of documentation.
+tests :: Bool
+tests = and $
+    (("file_1.txt" =~+ "^(.*)_(\\d).txt$") ==
+     [ ( "file_1.txt" , ( 0 , 10 ) )
+     , ( "file" , ( 0 , 4 ) )
+     , ( "1" , ( 5 , 1 ) )
+     ]) :
+
+    (("file_1.txt" =~- "^(.*)_(\\d).txt$") ==
+     ["file_1.txt", "file", "1"]) :
+
+    ("file_1.txt" =~# "^(.*)_(\\d).txt$") :
+
+    (let q :: LBS = "wif kwof ..wif,, wif,  8fwif"
+         p :: SBS = "\\Sw.f"
+     in ((q =~+ p) ==
+         [ ( "kwof" , (  4 , 4 ) ) ]) &&
+        ((q =~++ p) ==
+         [ [ ( "kwof" , (  4 , 4 ) ) ]
+         , [ ( ".wif" , ( 10 , 4 ) ) ]
+         , [ ( "fwif" , ( 24 , 4 ) ) ]
+         ])) :
+
+    (let q :: LBS = "wif kwof ..wif,, wif,  8fwif"
+         p :: SBS = "\\Sw.f"
+         f ([(a,_)] :: [(LBS, (MatchOffset, MatchLength))]) = Just $ "@" <> a <> "@"
+     in (replaceRegex q p f == "wif @kwof@ ..wif,, wif,  8fwif") &&
+        (replaceRegexAll q p f == "wif @kwof@ .@.wif@,, wif,  8@fwif@")) :
+
+    []
+
+
+type Match = SBS
+type Source = LBS
+
+
+-- | Convenience wrapper around '(=~)', that trades flexibility off
+-- for compactness.
+(=~+) :: Source -> Match -> [(Source, (MatchOffset, MatchLength))]
+(=~+) source match = elems (getAllTextSubmatches (source =~ match) :: MatchText Source)
+
+
+-- | Convenience wrapper for '(=~+)' that chops rarely needed offsets
+-- and lengths off the result.
+(=~-) :: Source -> Match -> [Source]
+(=~-) source match = map fst $ source =~+ match
+
+
+-- | Convenience function for '(=~+)' with match result 'Bool'.
+(=~#) :: Source -> Match -> Bool
+(=~#) source match = not . null $ source =~+ match
+
+
+-- | Like '(=~+)', but find all matches, not just the first one.
+(=~++) :: Source -> Match -> [[(Source, (MatchOffset, MatchLength))]]
+(=~++) source match = case source =~+ match of
+                        [] -> []
+                        x@((_, (holeStart, holeEnd)):_) -> x : map (shift (holeStart + holeEnd))
+                                                                   (LBS.drop (fromIntegral $ holeStart + holeEnd) source =~++ match)
+  where
+    shift :: Int -> [(Source, (MatchOffset, MatchLength))] -> [(Source, (MatchOffset, MatchLength))]
+    shift o' = map (\ (s, (o, l)) -> (s, (o + o', l)))
+
+
+-- | Replace first match with result of a function of the match.
+replaceRegex :: Source -> Match -> ([(Source, (MatchOffset, MatchLength))] -> Maybe Source) -> Source
+replaceRegex source match trans = case source =~+ match of
+      m@((_, (offset, length)):_) -> let before = LBS.take (fromIntegral offset) source
+                                         after = LBS.drop (fromIntegral $ offset + length) source
+                                     in case trans m of
+                                          Just m' -> before <> m' <> after
+                                          Nothing -> source
+
+
+-- | Replace all matches with result of a function of the match.
+replaceRegexAll :: Source -> Match -> ([(Source, (MatchOffset, MatchLength))] -> Maybe Source) -> Source
+replaceRegexAll source match trans = case source =~+ match of
+      [] -> source
+      m@((_, (offset, length)):_) -> case trans m of
+                                        Just m' -> let before = LBS.take (fromIntegral offset) source
+                                                       after  = LBS.drop (fromIntegral $ offset + length) source
+                                                   in before <> m' <> replaceRegexAll after match trans
+                                        Nothing -> let before = LBS.take (fromIntegral $ offset + length) source
+                                                       after  = LBS.drop (fromIntegral $ offset + length) source
+                                                   in before <> replaceRegexAll after match trans
diff --git a/regex-easy.cabal b/regex-easy.cabal
new file mode 100644
--- /dev/null
+++ b/regex-easy.cabal
@@ -0,0 +1,31 @@
+name:                regex-easy
+version:             0.1.0.0
+synopsis:            sugar for regex-pcre
+description:         This packages is intended to make perl developers happy to use Haskell.  (:
+license:             BSD3
+license-file:        LICENSE
+author:              Matthias Fischmann
+maintainer:          mf@zerobuzz.net
+copyright:           (c) 2014-2017 zerobuzz.net
+homepage:            https://github.com/zerobuzz/regex-easy
+category:            Data
+build-type:          Simple
+cabal-version:       >=1.10
+
+source-repository head
+  type: git
+  location: https://github.com/zerobuzz/regex-easy
+
+library
+  exposed-modules:
+    Text.Regex.Easy
+
+  build-depends:
+    base >= 4.6 && < 5,
+    array >= 0.4,
+    string-conversions >= 0.3,
+    bytestring >= 0.10,
+    regex-pcre >= 0.94
+
+  default-language:
+    Haskell2010
