diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright Yuji Yamamoto (c) 2017
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# substring-parser
+
+(WIP) Match / replace substrings with a parser combinators.
+
+Currently, supports only attoparsec.
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/src/Text/Parser/Substring.hs b/src/Text/Parser/Substring.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Parser/Substring.hs
@@ -0,0 +1,51 @@
+module Text.Parser.Substring
+  ( replaceFileOnceWithParser
+  , replaceOnceWithParser
+  , onceReplacify
+  ) where
+
+import           Control.Applicative ((<|>))
+import           Data.Attoparsec.Text
+import           Data.Maybe (fromMaybe)
+import           Data.Monoid ((<>), mempty)
+import           Data.Text (Text)
+import qualified Data.Text.Lazy as Text
+import qualified Data.Text.Lazy.Builder as TextBuilder
+import           Data.Text.Lazy.Builder (Builder)
+import qualified Data.Text.IO as Text
+
+import           Debug.NoTrace (trace)
+
+
+replaceFileOnceWithParser :: Parser Text -> FilePath -> IO ()
+replaceFileOnceWithParser p filePath =
+  Text.writeFile filePath =<< replaceOnceWithParser p <$> Text.readFile filePath
+
+
+-- TODO: 失敗した場合に元のテキストを返す
+replaceOnceWithParser :: Parser Text -> Text -> Text
+replaceOnceWithParser p =
+  Text.toStrict
+    . TextBuilder.toLazyText
+    . fromMaybe mempty
+    . maybeResult
+    . traceId "fed"
+    . flip feed ""
+    . traceId "parsed"
+    . parse (onceReplacify p)
+
+
+onceReplacify :: Parser Text -> Parser Builder
+onceReplacify p =
+  let firstToMatched =
+        (TextBuilder.fromText <$> p)
+          <|> ((<>) <$> (TextBuilder.singleton <$> anyChar) <*> firstToMatched)
+  in
+    (<>) <$> firstToMatched <*> (TextBuilder.fromText <$> takeText)
+
+
+traceIdVia :: Show b => (a -> b) -> String -> a -> a
+traceIdVia via prefix x = trace (prefix ++ ": " ++ show (via x)) x
+
+traceId :: Show a => String -> a -> a
+traceId = traceIdVia id
diff --git a/substring-parser.cabal b/substring-parser.cabal
new file mode 100644
--- /dev/null
+++ b/substring-parser.cabal
@@ -0,0 +1,48 @@
+-- This file has been generated from package.yaml by hpack version 0.17.1.
+--
+-- see: https://github.com/sol/hpack
+
+name:           substring-parser
+version:        0.1.0.0
+synopsis:       Match / replace substrings with a parser combinators.
+description:    See README.md
+category:       Text, Parsing
+homepage:       https://gitlab.com/igrep/substring-parser
+author:         Yuji Yamamoto
+maintainer:     whosekiteneverfly@gmail.com
+copyright:      2017 Yuji Yamamoto
+license:        Apache-2.0
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    README.md
+
+library
+  hs-source-dirs:
+      src
+  default-extensions: OverloadedStrings
+  build-depends:
+      base >= 4.7 && < 5
+    , NoTrace
+    , attoparsec
+    , text
+  exposed-modules:
+      Text.Parser.Substring
+  default-language: Haskell2010
+
+test-suite add-env-config-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      test
+  default-extensions: OverloadedStrings
+  build-depends:
+      base >= 4.7 && < 5
+    , NoTrace
+    , attoparsec
+    , text
+    , substring-parser
+    , hspec
+  default-language: Haskell2010
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,16 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import           Test.Hspec
+
+import           Text.Parser.Substring
+
+import           Control.Applicative ((*>))
+import           Data.Attoparsec.Text
+
+
+main :: IO ()
+main = hspec $
+  describe "replaceWithParser" $
+    it "replace first matching text by parser" $
+      replaceOnceWithParser (string "abc" *> pure "def") "--abc-abc-"
+        `shouldBe` "--def-abc-"
