diff --git a/Text/Parcom/ByteString/Lazy.hs b/Text/Parcom/ByteString/Lazy.hs
--- a/Text/Parcom/ByteString/Lazy.hs
+++ b/Text/Parcom/ByteString/Lazy.hs
@@ -7,6 +7,7 @@
 import Data.Word8
 import Text.Parcom.Stream
 import Text.Parcom.Word8
+import qualified Data.ByteString.Lazy.UTF8 as UTF8
 
 instance Stream ByteString Word8 where
     peek = head
@@ -16,3 +17,10 @@
 instance Listish ByteString Word8 where
     toList = unpack
     fromList = pack
+
+instance Textish ByteString where
+    peekChar s =
+        case UTF8.decode s of
+            Just ('\65533', _) -> (Nothing, 0)
+            Nothing -> (Nothing, 0)
+            Just (c, n) -> (Just c, fromIntegral n)
diff --git a/Text/Parcom/ByteString/Strict.hs b/Text/Parcom/ByteString/Strict.hs
--- a/Text/Parcom/ByteString/Strict.hs
+++ b/Text/Parcom/ByteString/Strict.hs
@@ -7,6 +7,7 @@
 import Data.Word8
 import Text.Parcom.Stream
 import Text.Parcom.Word8
+import Data.ByteString.UTF8 as UTF8
 
 instance Stream ByteString Word8 where
     peek = head
@@ -16,3 +17,10 @@
 instance Listish ByteString Word8 where
     toList = unpack
     fromList = pack
+
+instance Textish ByteString where
+    peekChar s =
+        case UTF8.decode s of
+            Just ('\65533', _) -> (Nothing, 0)
+            Nothing -> (Nothing, 0)
+            Just (c, n) -> (Just c, n)
diff --git a/Text/Parcom/Core.hs b/Text/Parcom/Core.hs
--- a/Text/Parcom/Core.hs
+++ b/Text/Parcom/Core.hs
@@ -8,12 +8,13 @@
 , try, handle
 , notFollowedBy
 , (<?>), (<|>), empty
-, Stream, Token, Listish
+, Stream, Token, Listish, Textish
+, peekChar, nextChar
 )
 where
 
 import qualified Text.Parcom.Stream as Stream
-import Text.Parcom.Stream (Stream, Token, Listish)
+import Text.Parcom.Stream (Stream, Token, Listish, Textish)
 import Control.Monad (liftM, ap)
 import Control.Applicative
 import Control.Monad.Identity
@@ -177,6 +178,24 @@
                 then modifyState $ \s -> s { psSourcePosition = nextLine (psSourcePosition s) }
                 else modifyState $ \s -> s { psSourcePosition = nextColumn (psSourcePosition s) }
             return t
+
+peekChar :: (Monad m, Stream s t, Token t, Textish s) => ParcomT s t m Char
+peekChar = do
+    str <- psStream `liftM` getState
+    let (charMay, _) = Stream.peekChar str
+    case charMay of
+        Just c -> return c
+        Nothing -> fail "Tokens do not form a valid character, or end of input reached"
+    
+nextChar :: (Monad m, Stream s t, Token t, Textish s) => ParcomT s t m Char
+nextChar = do
+    str <- psStream `liftM` getState
+    let (charMay, numTokens) = Stream.peekChar str
+    case charMay of
+        Just c -> do
+            replicateM_ numTokens next
+            return c
+        Nothing -> fail "Tokens do not form a valid character, or end of input reached"
 
 (<?>) :: (Monad m, Stream s t) => ParcomT s t m a -> String -> ParcomT s t m a
 p <?> expected = p <|> fail ("Expected " ++ expected)
diff --git a/Text/Parcom/Stream.hs b/Text/Parcom/Stream.hs
--- a/Text/Parcom/Stream.hs
+++ b/Text/Parcom/Stream.hs
@@ -29,3 +29,10 @@
 instance Listish [a] a where
     toList = id
     fromList = id
+
+class Textish s where
+    peekChar :: s -> (Maybe Char, Int)
+
+instance Textish [Char] where
+    peekChar [] = (Nothing, 0)
+    peekChar (c:[]) = (Just c, 1)
diff --git a/Text/Parcom/Text/Lazy.hs b/Text/Parcom/Text/Lazy.hs
--- a/Text/Parcom/Text/Lazy.hs
+++ b/Text/Parcom/Text/Lazy.hs
@@ -1,4 +1,4 @@
-{-#LANGUAGE MultiParamTypeClasses #-}
+{-#LANGUAGE MultiParamTypeClasses, OverloadedStrings #-}
 module Text.Parcom.Text.Lazy
 where
 
@@ -14,3 +14,7 @@
 instance Listish Text Char where
     toList = unpack
     fromList = pack
+
+instance Textish Text where
+    peekChar "" = (Nothing, 0)
+    peekChar s = (Just (head s), 1)
diff --git a/Text/Parcom/Text/Strict.hs b/Text/Parcom/Text/Strict.hs
--- a/Text/Parcom/Text/Strict.hs
+++ b/Text/Parcom/Text/Strict.hs
@@ -1,4 +1,4 @@
-{-#LANGUAGE MultiParamTypeClasses #-}
+{-#LANGUAGE MultiParamTypeClasses, OverloadedStrings #-}
 module Text.Parcom.Text.Strict
 where
 
@@ -14,3 +14,7 @@
 instance Listish Text Char where
     toList = unpack
     fromList = pack
+
+instance Textish Text where
+    peekChar "" = (Nothing, 0)
+    peekChar s = (Just (head s), 1)
diff --git a/parcom-lib.cabal b/parcom-lib.cabal
--- a/parcom-lib.cabal
+++ b/parcom-lib.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                parcom-lib
-version:             0.4.0.1
+version:             0.5.0.0
 synopsis:            A simple parser-combinator library, a bit like Parsec but without the frills
 description:         Parcom provides parser combinator functionality in a string-type-agnostic way;
                      it supports strict ByteStrings (with Word8 tokens) and any list type (with
@@ -41,3 +41,4 @@
                , mtl == 2.1.*
                , transformers >= 0.3 && < 1.0
                , text >= 0.11 && < 1.0
+               , utf8-string == 0.3.*
