diff --git a/simple-parser.cabal b/simple-parser.cabal
--- a/simple-parser.cabal
+++ b/simple-parser.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 1feb1774e0c1c145443c361947b747f9758ae9ba8257f9a5eae4818871d134d7
+-- hash: cae86899037beab7723314f49d8129dda7254a4261348de1d4b2e5ed8ebde7bf
 
 name:           simple-parser
-version:        0.2.0
+version:        0.2.1
 synopsis:       Simple parser combinators
 description:    Please see the README on GitHub at <https://github.com/ejconlon/simple-parser#readme>
 category:       Parsing
diff --git a/src/SimpleParser/Input.hs b/src/SimpleParser/Input.hs
--- a/src/SimpleParser/Input.hs
+++ b/src/SimpleParser/Input.hs
@@ -12,7 +12,9 @@
   , satisfyToken
   , foldTokensWhile
   , takeTokensWhile
+  , takeTokensWhile1
   , dropTokensWhile
+  , dropTokensWhile1
   , matchToken
   , matchChunk
   ) where
@@ -22,7 +24,7 @@
 import Data.Bifunctor (first)
 import Data.Maybe (isNothing)
 import SimpleParser.Parser (ParserT)
-import SimpleParser.Stream (Chunked (chunkLength), Stream (..))
+import SimpleParser.Stream (Chunked (..), Stream (..))
 
 -- | Return the next token, if any, but don't consume it.
 peekToken :: (Stream s, Monad m) => ParserT e s m (Maybe (Token s))
@@ -91,10 +93,20 @@
 takeTokensWhile :: (Stream s, Monad m) => (Token s -> Bool) -> ParserT e s m (Chunk s)
 takeTokensWhile = state . streamTakeWhile
 
+-- | Take tokens into a chunk while they satisfy the given predicate.
+-- Only succeeds if 1 or more tokens are taken, so it never returns an empty chunk.
+takeTokensWhile1 :: (Stream s, Monad m) => (Token s -> Bool) -> ParserT e s m (Chunk s)
+takeTokensWhile1 pcate = takeTokensWhile pcate >>= \c -> if chunkEmpty c then empty else pure c
+
 -- | Drop tokens and return chunk size while they satisfy the given predicate.
 -- Always succeeds, even at end of stream. May return empty chunk size 0.
 dropTokensWhile :: (Stream s, Monad m) => (Token s -> Bool) -> ParserT e s m Int
 dropTokensWhile = state . streamDropWhile
+
+-- | Drop tokens and return chunk size while they satisfy the given predicate.
+-- Only succeeds if 1 or more tokens are dropped.
+dropTokensWhile1 :: (Stream s, Monad m) => (Token s -> Bool) -> ParserT e s m Int
+dropTokensWhile1 pcate = dropTokensWhile pcate >>= \s -> if s == 0 then empty else pure s
 
 -- | Match token with equality or terminate the parser at inequality or end of stream.
 matchToken :: (Stream s, Monad m, Eq (Token s)) => Token s -> ParserT e s m (Token s)
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -474,12 +474,36 @@
         ]
   in testParserTrees parser cases
 
+test_take_while_1 :: [TestTree]
+test_take_while_1 =
+  let parser = takeTokensWhile1 (=='h') :: TestParser Text
+      cases =
+        [ ("empty", InputOutput "" [])
+        , ("non-match", InputOutput "i" [])
+        , ("match", InputOutput "hi" [parseSuccessResult "h" (OffsetStream 1 "i")])
+        , ("match 2", InputOutput "hhi" [parseSuccessResult "hh" (OffsetStream 2 "i")])
+        , ("match end", InputOutput "hh" [parseSuccessResult "hh" (OffsetStream 2 "")])
+        ]
+  in testParserTrees parser cases
+
 test_drop_while :: [TestTree]
 test_drop_while =
   let parser = dropTokensWhile (=='h') :: TestParser Int
       cases =
         [ ("empty", InputOutput "" [parseSuccessResult 0 (OffsetStream 0 "")])
         , ("non-match", InputOutput "i" [parseSuccessResult 0 (OffsetStream 0 "i")])
+        , ("match", InputOutput "hi" [parseSuccessResult 1 (OffsetStream 1 "i")])
+        , ("match 2", InputOutput "hhi" [parseSuccessResult 2 (OffsetStream 2 "i")])
+        , ("match end", InputOutput "hh" [parseSuccessResult 2 (OffsetStream 2 "")])
+        ]
+  in testParserTrees parser cases
+
+test_drop_while_1 :: [TestTree]
+test_drop_while_1 =
+  let parser = dropTokensWhile1 (=='h') :: TestParser Int
+      cases =
+        [ ("empty", InputOutput "" [])
+        , ("non-match", InputOutput "i" [])
         , ("match", InputOutput "hi" [parseSuccessResult 1 (OffsetStream 1 "i")])
         , ("match 2", InputOutput "hhi" [parseSuccessResult 2 (OffsetStream 2 "i")])
         , ("match end", InputOutput "hh" [parseSuccessResult 2 (OffsetStream 2 "")])
