How to Use Guava CharMatcher for Character Filtering and Matching: A Complete Guide
Guava's CharMatcher is an immutable predicate that provides a fluent API for matching, filtering, and transforming characters via factory methods, logical combinators, and pre-computed optimizations.
The CharMatcher class in Google's Guava library (google/guava) eliminates boilerplate when processing text by offering a rich set of utilities for character-level operations. Unlike regular expressions that operate on strings, CharMatcher works directly on primitive char values, making it ideal for high-performance text sanitization, validation, and extraction tasks. The implementation resides in guava/src/com/google/common/base/CharMatcher.java, with comprehensive usage patterns demonstrated in guava-tests/test/com/google/common/base/CharMatcherTest.java.
Creating CharMatcher Instances with Factory Methods
CharMatcher provides static factory methods that return specialized implementations for common character sets. Each factory returns a concrete subclass optimized for its specific matching logic, such as Any, None, Is, or InRange.
any()andnone(): Match all or no characters respectively.is(char match): Matches exactly one specific character.inRange(char start, char end): Matches any character within a continuous range.anyOf(CharSequence chars): Matches any character present in the given sequence.digit(),javaLetter(),whitespace(): Predefined matchers for common Unicode categories.
// Match specific characters
CharMatcher digit = CharMatcher.digit(); // Any Unicode digit
CharMatcher hexLower = CharMatcher.inRange('a', 'f'); // a through f
CharMatcher vowels = CharMatcher.anyOf("aeiouAEIOU"); // Any vowel
Composing Matchers with Logical Combinators
Complex matching logic is built using and(), or(), and negate() methods. These return composite instances (And, Or, Negated classes) that delegate matches(char) calls to their component matchers.
// Build a matcher for ASCII letters or digits, then negate it
CharMatcher notLetterOrDigit = CharMatcher.ascii()
.and(CharMatcher.inRange('a', 'z')
.or(CharMatcher.inRange('A', 'Z'))
.or(CharMatcher.inRange('0', '9')))
.negate();
// Hexadecimal matcher combining ranges
CharMatcher hex = CharMatcher.inRange('0', '9')
.or(CharMatcher.inRange('a', 'f'))
.or(CharMatcher.inRange('A', 'F'));
System.out.println(hex.matches('B')); // true
Text Processing with Utility Methods
CharMatcher provides text-processing methods that operate directly on CharSequence without manual looping. These implementations use indexIn internally to locate the first match, then process the remainder efficiently.
Removing unwanted characters:
String raw = "User_123!@#";
String cleaned = CharMatcher.anyOf("!@#").removeFrom(raw); // "User_123"
Retaining only matching characters:
String source = "a1b2c3";
String letters = CharMatcher.inRange('a', 'z').retainFrom(source); // "abc"
Trimming and collapsing:
String messy = "\t Hello World \n";
String tidy = CharMatcher.whitespace()
.trimAndCollapseFrom(messy, ' '); // "Hello World"
Replacing characters:
String result = CharMatcher.digit().replaceFrom("a1b2c3", '*'); // "a*b*c*"
Optimizing Performance with Pre-computation
For matchers used extensively in tight loops, call precomputed() to generate a fast lookup structure. According to the Guava source code, this invokes Platform.precomputeCharMatcher(this), which internally calls precomputedInternal() to select between SmallCharMatcher, BitSetMatcher, or a negated fast matcher based on the character set size.
CharMatcher fastMatcher = CharMatcher.anyOf("aeiou").precomputed();
The FastMatcher and NamedFastMatcher classes in the hierarchy indicate matchers that are already optimized. These subclasses override precomputed() to return this, bypassing redundant optimization.
Unicode and Supplementary Characters
CharMatcher operates exclusively on Basic Multilingual Plane (BMP) values. Supplementary Unicode characters (code points above U+FFFF) are treated as surrogate pairs, with each surrogate counted and matched separately in methods like countIn and matches(char).
Summary
- Factory methods like
anyOf(),inRange(), anddigit()create specialized matcher instances inCharMatcher.java. - Logical combinators (
and(),or(),negate()) compose simple matchers into complex predicates using delegate classes. - Text-processing methods (
removeFrom,retainFrom,trimAndCollapseFrom) provide one-line solutions for common string sanitization tasks. - Pre-computation via
precomputed()builds compactBitSetor hash table structures for constant-timematches(char)lookups. - BMP limitation:
CharMatcherhandles supplementary Unicode characters as individual surrogate pairs rather than single code points.
Frequently Asked Questions
How does CharMatcher differ from Java's regular expressions?
CharMatcher operates on individual primitive char values rather than string patterns, providing better performance for single-character classification and offering specialized text-processing methods (collapseFrom, trimAndCollapseFrom) that would require complex regex replacement logic. Unlike Pattern and Matcher, CharMatcher instances are immutable and thread-safe by design, allowing reuse across multiple threads without synchronization.
When should I call precomputed() on a CharMatcher?
Call precomputed() when you will use the same CharMatcher instance repeatedly in performance-critical code paths, such as processing large files or high-throughput data streams. The optimization builds a compact BitSet or hash table that reduces matches(char) lookup time from predicate evaluation to constant-time array access. Simple matchers returned by any(), none(), or is() already extend FastMatcher and automatically bypass pre-computation.
How do I create a custom CharMatcher for a specific predicate?
Use CharMatcher.forPredicate(Predicate<? super Character> predicate) to wrap a custom condition, or subclass CharMatcher directly and override the matches(char c) method. When subclassing, consider also overriding toString() for debugging and extending NamedFastMatcher if your implementation is inherently fast and should skip pre-computation optimization.
Does CharMatcher support Unicode emoji or supplementary characters?
No, CharMatcher only processes 16-bit char values from the Basic Multilingual Plane. Supplementary characters such as emoji (code points U+10000 and above) are represented as surrogate pairs in Java, and CharMatcher treats each surrogate as an independent character. For example, countIn() will return 2 for a single emoji character. Use Java's CodePoint APIs or IntStream for proper supplementary character handling when working with characters outside the BMP.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →