diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+7.1.1
+
+* Added `charsKeptIf` and `charsRemovedIf`.
+
 7.1.0
 
 * Added common container formatter combinators: `maybed`, `optioned`, `eithered`, `lefted`, and `righted`.
diff --git a/formatting.cabal b/formatting.cabal
--- a/formatting.cabal
+++ b/formatting.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.4
 name:                formatting
-version:             7.1.0
+version:             7.1.1
 synopsis:            Combinator-based type-safe formatting (like printf() or FORMAT)
 description:         Combinator-based type-safe formatting (like printf() or FORMAT), modelled from the HoleyMonoids package.
                      .
diff --git a/src/Formatting/Combinators.hs b/src/Formatting/Combinators.hs
--- a/src/Formatting/Combinators.hs
+++ b/src/Formatting/Combinators.hs
@@ -49,6 +49,8 @@
 
   -- * Altering formatted strings
   , alteredWith
+  , charsKeptIf
+  , charsRemovedIf
   , replaced
   , uppercased
   , lowercased
@@ -344,6 +346,20 @@
 alteredWith :: (Text -> Text) -> Format r a -> Format r a
 alteredWith alterer f =
   later (TLB.toLazyText >>> alterer >>> TLB.fromLazyText) %. f
+
+-- | Filter the formatted string to contain only characters which pass the given predicate:
+--
+-- >>> format (charsKeptIf Data.Char.isUpper text) "Data.Char.isUpper"
+-- "DCU"
+charsKeptIf :: (Char -> Bool) -> Format r a -> Format r a
+charsKeptIf p = alteredWith (TL.filter p)
+
+-- | Filter the formatted string to not contain characters which pass the given predicate:
+--
+-- >>> format (charsRemovedIf Data.Char.isUpper text) "Data.Char.isUpper"
+-- "ata.har.ispper"
+charsRemovedIf :: (Char -> Bool) -> Format r a -> Format r a
+charsRemovedIf p = alteredWith (TL.filter (not . p))
 
 -- | Take a formatter and replace the given needle with the given replacement in its output.
 --
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -2,7 +2,7 @@
 {-# OPTIONS -Wno-type-defaults #-}
 
 import Control.Monad
-import Data.Char (isSpace)
+import Data.Char (isSpace, isUpper)
 import Data.Int
 import qualified Data.Monoid
 import Data.Scientific
@@ -159,6 +159,8 @@
 
   describe "altering combinators" $ do
     it "alteredWith" $ format (alteredWith LT.reverse int) 123456 `shouldBe` "654321"
+    it "charsKeptIf" $ format (charsKeptIf isUpper text) "Data.Char.isUpper" `shouldBe` "DCU"
+    it "charsRemovedIf" $ format (charsRemovedIf isUpper text) "Data.Char.isUpper" `shouldBe` "ata.har.ispper"
     it "replaced" $ format (replaced "Bruce" "<redacted>" stext) "Bruce replied that Bruce's name was, in fact, '<redacted>'." `shouldBe` "<redacted> replied that <redacted>'s name was, in fact, '<redacted>'."
     it "uppercased" $ format (uppercased text) "I'm not shouting, you're shouting." `shouldBe` "I'M NOT SHOUTING, YOU'RE SHOUTING."
     it "lowercased" $ format (lowercased text) "Cd SrC/; Rm -Rf *" `shouldBe` "cd src/; rm -rf *"
