diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for bytesmith
 
+## 0.3.14.0 -- 2025-11-17
+
+* Add `take` for ASCII parser.
+
 ## 0.3.13.0 -- 2025-07-11
 
 * Add `hexFixedWord16#`
diff --git a/bytesmith.cabal b/bytesmith.cabal
--- a/bytesmith.cabal
+++ b/bytesmith.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.0
 name:            bytesmith
-version:         0.3.13.0
+version:         0.3.14.0
 synopsis:        Nonresumable byte parser
 description:
   Parse bytes as fast as possible. This is a nonresumable parser
@@ -16,7 +16,7 @@
 copyright:       2019 Andrew Martin
 category:        Data
 extra-doc-files: CHANGELOG.md
-tested-with:     GHC ==9.4.8 || ==9.6.3 || ==9.8.1
+tested-with:     GHC ==9.6.3 || ==9.8.1
 
 common build-settings
   default-language: Haskell2010
@@ -48,6 +48,7 @@
     , natural-arithmetic  >=0.1.3
     , primitive           >=0.7     && <0.10
     , text-short          >=0.1.3   && <0.2
+    , text                >=0.2.1
     , wide-word           >=0.1.0.9 && <0.2
 
   hs-source-dirs:  src
diff --git a/src/Data/Bytes/Parser/Ascii.hs b/src/Data/Bytes/Parser/Ascii.hs
--- a/src/Data/Bytes/Parser/Ascii.hs
+++ b/src/Data/Bytes/Parser/Ascii.hs
@@ -32,6 +32,7 @@
   , opt
 
     -- * Match Many
+  , take
   , shortTrailedBy
   , takeShortWhile
 
@@ -52,7 +53,7 @@
   , Latin.decWord32
   ) where
 
-import Prelude hiding (any, fail, length, takeWhile)
+import Prelude hiding (any, fail, length, takeWhile, take)
 
 import Control.Monad.ST (runST)
 import Data.Bits (clearBit)
@@ -62,9 +63,11 @@
 import Data.Text.Short (ShortText)
 import Data.Word (Word8)
 import GHC.Exts (Char (C#), Char#, Int (I#), Int#, chr#, gtChar#, indexCharArray#, ord#, (+#), (-#), (<#))
+import Data.Text.Internal (Text(Text))
 
 import qualified Data.ByteString.Short.Internal as BSS
 import qualified Data.Bytes as Bytes
+import qualified Data.Bytes.Parser as Parser
 import qualified Data.Bytes.Parser.Latin as Latin
 import qualified Data.Bytes.Parser.Unsafe as Unsafe
 import qualified Data.Primitive as PM
@@ -102,6 +105,15 @@
           then pure ()
           else go
   go
+
+-- | Consume a fixed number of ASCII characters (all less than codepoint 128).
+take :: e -> Int -> Parser e s Text
+{-# INLINE take #-}
+take e !n = do
+  bs@(Bytes arr off len) <- Parser.take e n
+  if Bytes.all (\w -> w < 128) bs
+    then pure (Text arr off len)
+    else Parser.fail e
 
 {- | Consume characters matching the predicate. The stops when it
 encounters a non-matching character or when it encounters a byte
