@@ -51,12 +51,19 @@ module Data.Attoparsec.Text
5151 , I.satisfyWith
5252 , I.skip
5353
54+ -- ** Special character parsers
55+ , digit
56+ , letter
57+ , space
58+
5459 -- ** Character classes
5560 , I.inClass
5661 , I.notInClass
5762
5863 -- * Efficient string handling
5964 , I.string
65+ , stringCI
66+ , skipSpace
6067 , I.skipWhile
6168 , I.scan
6269 , I.take
@@ -90,9 +97,9 @@ module Data.Attoparsec.Text
9097import Control.Applicative ((<$>), (*>), (<|>))
9198import Data.Attoparsec.Combinator
9299import Data.Attoparsec.Number (Number(..))
93−import Data.Attoparsec.Text.Internal (Parser, Result, parse, takeWhile1)
100+import Data.Attoparsec.Text.Internal ((<?>), Parser, Result, parse, takeWhile1)
94101import Data.Bits (Bits, (.|.), shiftL)
95−import Data.Char (ord)
102+import Data.Char (isAlpha, isDigit, isSpace, ord)
96103import Data.Int (Int8, Int16, Int32, Int64)
97104import Data.Ratio ((%))
98105import Data.Text (Text)
@@ -264,7 +271,7 @@ hexadecimal = T.foldl' step 0 `fmap` takeWhile1 isHexDigit
264271
265272-- | Parse and decode an unsigned decimal number.
266273decimal :: Integral a => Parser a
267−decimal = T.foldl' step 0 `fmap` takeWhile1 isDigit
274+decimal = T.foldl' step 0 `fmap` takeWhile1 isDecimal
268275 where step a c = a * 10 + fromIntegral (ord c - 48)
269276{-# SPECIALISE decimal :: Parser Int #-}
270277{-# SPECIALISE decimal :: Parser Int8 #-}
@@ -278,9 +285,9 @@ decimal = T.foldl' step 0 `fmap` takeWhile1 isDigit
278285{-# SPECIALISE decimal :: Parser Word32 #-}
279286{-# SPECIALISE decimal :: Parser Word64 #-}
280287
281−isDigit :: Char -> Bool
282−isDigit c = c >= '0' && c <= '9'
283−{-# INLINE isDigit #-}
288+isDecimal :: Char -> Bool
289+isDecimal c = c >= '0' && c <= '9'
290+{-# INLINE isDecimal #-}
284291
285292-- | Parse a number with an optional leading @\'+\'@ or @\'-\'@ sign
286293-- character.
@@ -370,6 +377,31 @@ number = floaty $ \real frac fracDenom ->
370377 else D (asDouble real frac fracDenom)
371378{-# INLINE number #-}
372379
380+-- | Parse a single digit, as recognised by 'isDigit'.
381+digit :: Parser Char
382+digit = I.satisfy isDigit <?> "digit"
383+{-# INLINE digit #-}
384+
385+-- | Parse a letter, as recognised by 'isAlpha'.
386+letter :: Parser Char
387+letter = I.satisfy isAlpha <?> "letter"
388+{-# INLINE letter #-}
389+
390+-- | Parse a space character, as recognised by 'isSpace'.
391+space :: Parser Char
392+space = I.satisfy isSpace <?> "space"
393+{-# INLINE space #-}
394+
395+-- | Satisfy a literal string, ignoring case.
396+stringCI :: Text -> Parser Text
397+stringCI = I.stringTransform T.toCaseFold
398+{-# INLINE stringCI #-}
399+
400+-- | Skip over white space.
401+skipSpace :: Parser ()
402+skipSpace = I.skipWhile isSpace
403+{-# INLINE skipSpace #-}
404+
373405data T = T !Integer !Int
374406
375407floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Parser a