diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
 
 import Marvin.Interpolate
 
-myStr = [iq|some string %{show $ map succ [1,2,3]} and data |]
+myStr = [iq|some string #{show $ map succ [1,2,3]} and data |]
 -- "some string [2,3,4] and data"
 ```
 
@@ -26,11 +26,11 @@
 
 import Marvin.Interpolate
 
-myStr = $(is "some string %{show $ map succ [1,2,3]} and data")
+myStr = $(is "some string #{show $ map succ [1,2,3]} and data")
 -- "some string [2,3,4] and data"
 ```
 
-It basically transforms the interpolated string  `[iq|interpolated string|]`, or in splices `$(is "interpolated string")` into a concatenation of all string bits and the expressions in `%{}`.
+It basically transforms the interpolated string  `[iq|interpolated string|]`, or in splices `$(is "interpolated string")` into a concatenation of all string bits and the expressions in `#{}`.
 Therefore it is not limited to `String` alone, rather it produces a literal at compile time, which can either be interpreted as `String` or, using the [`OverloadedStrings`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#overloaded-string-literals) extension, as `Text` or `ByteString` or any other string type.
 
 `i` (for *interpolate quoter*) and `is` (for *interpolate splice*) is the basic interpolator, which inserts the expressions verbatim. Hence when using `iq` or `is` all expressions must return the desired string type.
@@ -53,28 +53,23 @@
 Interpolation uses the quasi quoter sytax, which starts with `[interpolator_name|` and ends with `|]` or splice syntax `$(interpolator "interpolated string")`.
 Anything in between is interpreted by the library.
 
-The format string in between uses the syntax `%{expression}`.
+The format string in between uses the syntax `#{expression}`.
 Any valid Haskell expression can be used inside the braces.
 And all names which are in scope can be used, like so.
 
 ```haskell
-let x = 5 in [iS|x equals %{x}|] -- > "x equals 5"
+let x = 5 in [iS|x equals #{x}|] -- > "x equals 5"
 ```
 
-There are four escape sequences to allow literal `%{` and `|]`
+There are four escape sequences to allow literal `#{` and `|]`
 
 | Input | Output |
 |-------|--------|
-| `~]`  | `]`    |
-| `~%`  | `%`    |
-| `~}`  | `}`    | 
-| `~~`  | `~`    |
+| `#]`  | `]`    |
+| `##`  | `#`    |
 
 
-As a result the sequence `~%{` will show up as a literal `%{` in the output and `|~]` results in a literal `|]`.
-Note that these are simple substitutions. 
-In general the characters themselves, if not escaped, will not throw errors, aka `~` will be `~` again in the output.
-Escaping is only necessary in cases where these cahracters would have a special meaning otherwise.
+As a result the sequence `##{` will show up as a literal `#{` in the output and `|#]` results in a literal `|]`.
 
 
 ## Differences to/Advantages over other libraries
diff --git a/marvin-interpolate.cabal b/marvin-interpolate.cabal
--- a/marvin-interpolate.cabal
+++ b/marvin-interpolate.cabal
@@ -1,5 +1,5 @@
 name: marvin-interpolate
-version: 0.3.0
+version: 0.4.0
 cabal-version: >=1.10
 build-type: Simple
 license: BSD3
@@ -43,7 +43,7 @@
     main-is: Spec.hs
     build-depends:
         base >=4.9.0.0 && <4.10,
-        marvin-interpolate >=0.3.0 && <0.4,
+        marvin-interpolate >=0.4.0 && <0.5,
         hspec >=2.2.4 && <2.3,
         text >=1.2.2.1 && <1.3
     default-language: Haskell2010
diff --git a/src/Marvin/Interpolate.hs b/src/Marvin/Interpolate.hs
--- a/src/Marvin/Interpolate.hs
+++ b/src/Marvin/Interpolate.hs
@@ -15,6 +15,7 @@
   , iq
   -- * Internals/extension points
   , interpolateInto
+  , parser
   ) where
 
 
@@ -36,41 +37,56 @@
 escapeChar :: Char
 escapeChar = '~'
 
+type ParseM = Parsec String Int
 
-parser :: Parsec String () Parsed
+
+parser :: ParseM Parsed
 parser = manyTill (parseInterpolation <|> parseString) eof
 
-parseString :: Parsec String () (Either String String)
-parseString = Right <$> parseTillEscape "%{" True
+parseString :: ParseM (Either String String)
+parseString = do
+    chunk <- many $ noneOf ['#']
+    fmap (Right . (chunk ++)) $ (eof >> return "") <|> (lookAhead (try (char '#' >> anyChar)) >>= endOrEscape) <|> fmap return anyChar
+  where
+    endOrEscape :: Char -> ParseM String
+    endOrEscape '{' = return ""
+    endOrEscape '#' = count 2 anyChar >> return "#"
+    endOrEscape ']' = count 2 anyChar >> return "]"
+    endOrEscape _ = fail ""
 
-parseInterpolation :: Parsec String () (Either String String)
-parseInterpolation = Left <$> between (try $ string "%{") (char '}') (parseTillEscape "}" False)
 
-parseTillEscape :: String -> Bool -> Parsec String () String
-parseTillEscape endSeq@(endChar:_) allowEOF = do
-    chunk <- many $ noneOf [escapeChar, endChar]
-    rest <- eofEND
-              <|> (char escapeChar >> parseEscaped)
-              <|> (lookAhead (try $ string endSeq) >> return "")
-              <|> (return <$> char endChar)
-    return $ chunk <> rest
+parseInterpolation :: ParseM (Either String String)
+parseInterpolation = (try $ string "#{") >> (Left <$> parseExpr)
   where
-    eofEND
-        | allowEOF = eof >> return "" -- <|> (try (char escapeChar >> eof) >> char escapeChar >> return [escapeChar])
-        | otherwise = fail "EOF not allowed in interpolation"
+    parseExpr = do
+        chunk <- many $ noneOf ['}', '"', '\'', '{']
+        fmap (chunk ++) $ (eof >> error "eof in interpolation") <|> (anyChar >>= continue)
 
-    parseEscaped = (eof >> return [escapeChar]) <|> do
-        next <- anyChar
-        let escaped
-                | next == escapeChar = [escapeChar]
-                | next == '%' = "%"
-                | next == ']' = "]"
-                | next == '}' = "}"
-                | otherwise = escapeChar : [next]
-        rest <- parseTillEscape endSeq allowEOF
-        return $ escaped <> rest
+    continue :: Char -> ParseM String
+    continue '{' = modifyState succ >> fmap ('{':) parseExpr
+    continue '}' = do
+        s <- getState
+        if s == 0
+          then return ""
+          else ('}':) <$> (modifyState succ >> parseExpr)
+    continue '\"' = ('"':) <$> parseStr
+    continue '\'' = do
+        char '\''
+        inner <- ((:) <$> char '\\' <*> fmap return anyChar) <|> fmap return anyChar
+        char '\''
+        return $ '\'':inner ++ "'"
 
+    parseStr = do
+        chunk <- many $ noneOf ['"', '\\']
+        fmap (chunk ++) $ (eof >>= fail "eof in string literal") 
+                          <|> (anyChar >>= continueStr)
+      where 
+        continueStr '"' = ('"':) <$> parseExpr
+        continueStr '\\' = do
+            escaped <- anyChar
+            (\a -> '\\':escaped:a) <$> parseStr
 
+
 evalExprs :: Parsed -> [Either Exp String]
 evalExprs l = evalState (mapM stitch l) decls
   where
@@ -103,7 +119,7 @@
     foldl f (LitE (StringL "")) interleaved
 
   where
-    parsed = either (error . show) id $ parse parser "inline" str
+    parsed = either (error . show) id $ runParser parser 0 "inline" str
     interleaved = evalExprs parsed
 
     f expr bit = AppE (VarE 'mappend) expr `AppE` bitExpr
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -28,26 +28,14 @@
 main :: IO ()
 main = hspec $ do
     describe "parsing to itself" $ do
-        it "%" $
-            [iq|%|] `shouldBe` "%"
-        it "%anything" $
-            [iq|%anything|] `shouldBe` "%anything"
-        it "~" $
-            [iq|~|] `shouldBe` "~"
-        it "~anything" $
-            $(is "~anything") `shouldBe` "~anything"
+        it "#" $
+            [iq|#|] `shouldBe` "#"
+        it "#anything" $
+            [iq|#anything|] `shouldBe` "#anything"
 
-    describe "parsing escape sequences" $ do
-        it "parses ~% as %" $
-            [iq|~%|] `shouldBe` "%"
-        it "parses ~] as ]" $
-            [iq|~]|] `shouldBe` "]"
-        it "parses ~%{} as %{}" $
-            [iq|~%{}|] `shouldBe` "%{}"
-        it "parses |~] as |]" $
-            [iq||~]|] `shouldBe` "|]"
-        it "parses ~~ as ~" $
-            [iq|~~|] `shouldBe` "~"
+    describe "parsing escape sequences" $
+        it "parses ## as #" $
+            [iq|##|] `shouldBe` "#"
 
     describe "interpolation substitution" $ do
         it "leaves an empty string" $
@@ -56,32 +44,32 @@
             [iq|this is not changed|] `shouldBe` "this is not changed"
         it "interpolates just an external variable" $
             let y = "str" in
-                [iq|%{y}|] `shouldBe` y
+                [iq|#{y}|] `shouldBe` y
         it "interpolates an external variable" $
-            let y = "str2" in [iq| hello you %{y} end|] `shouldBe` " hello you " ++ y ++ " end"
+            let y = "str2" in [iq| hello you #{y} end|] `shouldBe` " hello you " ++ y ++ " end"
         it "interpolates the variable x (used to be special)" $
-            let x = "str" in [iq| hello x: %{x}|] `shouldBe` " hello x: " ++ x
+            let x = "str" in [iq| hello x: #{x}|] `shouldBe` " hello x: " ++ x
         it "interpolates infix with $" $
-            [iq|str %{show $ 4 + (5 :: Int)} str|] `shouldBe` "str 9 str"
+            [iq|str #{show $ 4 + (5 :: Int)} str|] `shouldBe` "str 9 str"
         it "interpolates multiple bindings" $
             let
                 x = "multiple"
                 y = "can"
                 z = "local scope"
-            in [iq|We %{y} interpolate %{x} bindings from %{z}|]
+            in [iq|We #{y} interpolate #{x} bindings from #{z}|]
                 `shouldBe` "We can interpolate multiple bindings from local scope"
 
         it "interpolates complex expressions" $
             let
                 x = ["haskell", "expression"]
                 y = " can be"
-            in [iq|Any %{intercalate " " x ++ y} interpolated|]
+            in [iq|Any #{intercalate " " x ++ y} interpolated|]
                  `shouldBe` "Any haskell expression can be interpolated"
 
 
     describe "splice interpolation" $
         it "interpolates a splice" $
-            let x = 5 :: Int in $(isS "%{x}") `shouldBe` "5"
+            let x = 5 :: Int in $(isS "#{x}") `shouldBe` "5"
     
     describe "'is' generic interpolation" $ do
         it "to string" $
@@ -95,24 +83,24 @@
 
     describe "'isS' interpolation to String" $ do
         it "calls show on Int" $
-            $(isS "%{x}") `shouldBe` "5"
+            $(isS "#{x}") `shouldBe` "5"
         it "calls showStr if available" $
-            $(isS "%{G}") `shouldBe` "showStr"
+            $(isS "#{G}") `shouldBe` "showStr"
         it "does not change Text" $
-            $(isS "%{\"str\" :: T.Text}") `shouldBe` "str"
+            $(isS "#{\"str\" :: T.Text}") `shouldBe` "str"
 
     describe "'isT' interpolation to Text" $ do
         it "calls show on Int" $
-            $(isT "%{x}") `shouldBe` "5"
+            $(isT "#{x}") `shouldBe` "5"
         it "calls showT if available" $
-            $(isT "%{G}") `shouldBe` "showT"
+            $(isT "#{G}") `shouldBe` "showT"
         it "does not change Text" $
-            $(isT "%{\"str\" :: T.Text}") `shouldBe` "str"
+            $(isT "#{\"str\" :: T.Text}") `shouldBe` "str"
 
     describe "'isL' interpolation to lazy Text" $ do
         it "calls show on Int" $
-            $(isL "%{x}") `shouldBe` "5"
+            $(isL "#{x}") `shouldBe` "5"
         it "calls showStr if available" $
-            $(isL "%{G}") `shouldBe` "showL"
+            $(isL "#{G}") `shouldBe` "showL"
         it "does not change Text" $
-            $(isL "%{\"str\" :: T.Text}") `shouldBe` "str"
+            $(isL "#{\"str\" :: T.Text}") `shouldBe` "str"
