A regex word boundary, written \b, is a position where a word character meets a non-word character or the edge of the text. It lets a pattern find “cat” as a separate word while it skips the “cat” inside “category”. Like ^ and $, the word boundary is an anchor, so it matches a position and consumes no characters.
We use \b in Java regular expressions to search for whole words, to find words that start or end with given letters, and to filter log lines by their first word. The following example runs the most common word boundary patterns, and the comment on each line shows the result.
boolean whole = Pattern.compile("\\bcat\\b").matcher("the cat sat").find(); // true
boolean inside = Pattern.compile("\\bcat\\b").matcher("category").find(); // false
List<String> starts = Pattern.compile("\\bun\\w*").matcher("undo the unknown fun")
.results().map(MatchResult::group).toList(); // [undo, unknown]
List<String> ends = Pattern.compile("\\w+ing\\b").matcher("walking and talking in the morning")
.results().map(MatchResult::group).toList(); // [walking, talking, morning]
Notice that the pattern \bun\w* skips the “un” at the end of “fun”, because no word starts there. We start with the positions where \b matches and the characters that count as word characters, look at prefixes, suffixes and whole lines, and finish with \B, \G and the mistakes that make a word boundary fail in Java.
In Java source code, every backslash of a pattern is doubled inside the string literal, so each pattern has a regex form and a Java string form.
| To find | Regex | Java string literal |
|---|---|---|
| The whole word “cat” | \bcat\b | “\\bcat\\b” |
| Words starting with “un” | \bun\w* | “\\bun\\w*” |
| Words ending with “ing” | \w+ing\b | “\\w+ing\\b” |
| “cat” inside a longer word | \Bcat\B | “\\Bcat\\B” |
| Lines starting with the word “ERROR” | (?m)^ERROR\b.* | “(?m)^ERROR\\b.*” |
1. The Three Positions Where \b Matches
A word character is a letter, a digit or the “_” character, the same set as \w. The anchor \b matches at three kinds of positions, and nowhere else.

- Before the first character of the text, if that character is a word character.
- After the last character of the text, if that character is a word character.
- Between two characters where one is a word character and the other is not.
Replacing each boundary with a “|” makes the positions visible. In “cat sat”, the boundaries sit on both sides of each word, so the space has a boundary on each side.
String marked = "cat sat".replaceAll("\\b", "|"); // "|cat| |sat|"
String notMarked = "a cat".replaceAll("\\B", "|"); // "a c|a|t"
The anchor \B is the opposite of \b. It matches at every position that is not a word boundary, which in “a cat” are the two positions between the letters of “cat”.
A boundary before a word character is the start of a word, and a boundary after a word character is the end of a word. So \b\w finds the first letter of each word and \w\b finds the last one. To keep the next snippets short, we wrap the stream call in a small findAll() helper.
static List<String> findAll(String regex, String text) {
return Pattern.compile(regex).matcher(text).results().map(MatchResult::group).toList();
}
List<String> firstLetters = findAll("\\b\\w", "hello big world"); // [h, b, w]
List<String> lastLetters = findAll("\\w\\b", "hello big world"); // [o, g, d]
2. Hyphens, Apostrophes and Accented Letters
The anchor \b follows the regex definition of a word, which is not the English one. Only [a-zA-Z0-9_] count as word characters by default, so a hyphen or an apostrophe splits a word into two.
String hyphen = "e-mail".replaceAll("\\b", "|"); // "|e|-|mail|"
String apostrophe = "don't".replaceAll("\\b", "|"); // "|don|'|t|"
String underscore = "user_1".replaceAll("\\b", "|"); // "|user_1|"
As a result, \bmail\b finds “mail” inside “e-mail”, and \bt\b finds the “t” of “don\’t”. When a hyphen should count as part of a word, we replace \b with lookaround that treats the hyphen as a word character.
boolean plain = Pattern.compile("\\bmail\\b").matcher("my e-mail").find(); // true
boolean hyphenAware = Pattern.compile("(?<![\\w-])mail(?![\\w-])").matcher("my e-mail").find(); // false
boolean alone = Pattern.compile("(?<![\\w-])mail(?![\\w-])").matcher("mail box").find(); // true
The lookbehind (?<![\w-]) means “not preceded by a word character or a hyphen”, and the lookahead (?![\w-]) means the same for the next character. We use the same technique for words that end with a symbol in section 7.
Accented letters are not word characters by default either. Since Java 19, \b uses the same ASCII definition as \w (JDK-8264160). In the French word “ete” written with two accented “e” letters (U+00E9), only the plain “t” counts as a word. The flag UNICODE_CHARACTER_CLASS, inline (?U), makes both \w and \b follow Unicode rules.
String ete = "\u00e9t\u00e9";
List<String> asciiWords = findAll("\\b\\w+\\b", ete); // [t]
List<String> unicodeWords = findAll("(?U)\\b\\w+\\b", ete); // [\u00e9t\u00e9]
For text in languages other than English, we add (?U) to every pattern that uses \b or \w. A product search in a French or German shop otherwise splits a name such as “creme”, written with an accented “e”, into pieces and never finds it as a whole word.
3. Words That Start With Given Letters
To find words that start with a prefix, we put \b before the prefix and \w* after it. The \b makes the prefix the start of a word, and \w* takes the rest of the word.
List<String> withBoundary = findAll("\\bun\\w*", "undo the unknown fun"); // [undo, unknown]
List<String> noBoundary = findAll("un\\w*", "undo the unknown fun"); // [undo, unknown, un]
List<String> anyCase = findAll("(?i)\\bun\\w*", "Undo the unknown fun"); // [Undo, unknown]
The second pattern has no \b, so it also matches the “un” at the end of “fun”. The third pattern adds (?i) to ignore case. A character class works as the prefix too, so \b[A-Z]\w* finds the words that start with a capital letter.
List<String> capitalized = findAll("\\b[A-Z]\\w*", "Lokesh lives in Delhi"); // [Lokesh, Delhi]
A recipe app gives a real use for a prefix search. When the user types “to” into the ingredient filter, the app suggests “tomato” and “tofu” but not “potato”. The prefix comes from user input, so we quote it with Pattern.quote() before we put it into the pattern, and a typed “c++” cannot break the regex.
String typed = "to";
Pattern suggest = Pattern.compile("(?i)\\b" + Pattern.quote(typed) + "\\w*");
List<String> hints = suggest.matcher("potato, tomato, tofu").results().map(MatchResult::group).toList(); // [tomato, tofu]
4. Words That End With Given Letters
For a suffix, the boundary goes after it, as in \w+ing\b. We use \w+ instead of \w* when the suffix alone should not count as a word, so “ing” by itself is not a match.
List<String> ingWords = findAll("\\w+ing\\b", "walking and talking in the morning"); // [walking, talking, morning]
List<String> strict = findAll("\\w+ing\\b", "singing birds and a kingdom"); // [singing]
List<String> loose = findAll("\\w+ing", "singing birds and a kingdom"); // [singing, king]
Without the final \b, the pattern returns “king” from “kingdom”, a word that does not end with “ing”.
Say a writing tool for a team blog marks adverbs that end with “ly”, so authors can cut them. The pattern (?i)\b\w+ly\b finds “Sadly” and “slowly” but skips “lyrics”. The word “only” is a match too, so the tool shows hints and leaves the decision to the author, because a suffix rule cannot know English grammar.
List<String> adverbs = findAll("(?i)\\b\\w+ly\\b", "Sadly, we slowly read the lyrics only"); // [Sadly, slowly, only]
5. Lines That Start or End With a Word
A common task is to filter log lines by the word they start with. The line anchors ^ and $ with MULTILINE mode select the line, and \b makes sure the first word is the one we want and not a longer word.
String log = """
ERROR disk full
INFO started
ERRORS: 0
WARN retry done""";
List<String> prefixOnly = findAll("(?m)^ERROR.*", log); // [ERROR disk full, ERRORS: 0]
List<String> wholeWord = findAll("(?m)^ERROR\\b.*", log); // [ERROR disk full]
List<String> endsWith = findAll("(?m)^.*\\bdone$", log); // [WARN retry done]
The first pattern also returns the third line, because “ERRORS” starts with “ERROR”. The \b after “ERROR” requires a non-word character next, so “ERRORS” no longer matches. In the last pattern, \b before “done” rejects a line that ends with, for example, “undone”. The article on regex start and end of line explains ^, $ and MULTILINE in detail.
6. Matching Inside a Word With \B
The anchor \B requires the pattern to be part of a longer word. The pattern \Bcat\B finds “cat” only when there are word characters on both sides, and \Bcat finds “cat” at the end or in the middle of a word, but not at its start.
List<String> middle = findAll("\\Bcat\\B", "concatenate cat"); // [cat]
boolean atEnd = Pattern.compile("\\Bcat").matcher("concat").find(); // true
boolean atStart = Pattern.compile("\\Bcat").matcher("cat").find(); // false
The single match in the first line comes from “concatenate”. The separate word “cat” fails, because a word boundary sits on both of its sides.
7. Mistakes That Make the Word Boundary Fail
Most “my word boundary does not work” problems in Java come from one of three causes. The code compiles in each case, so the bug shows up only as a search that never finds anything.
7.1. A Single Backslash in the Java String
In a Java string literal, “\b” is the backspace character (U+0008), not a regex word boundary. The pattern searches for a backspace, and it never matches normal text. The regex needs “\\b” with two backslashes in Java source code.
boolean backspace = "\b".equals("\u0008"); // true
boolean wrong = Pattern.compile("\bcat\b").matcher("the cat").find(); // false
boolean right = Pattern.compile("\\bcat\\b").matcher("the cat").find(); // true
7.2. A Word That Starts or Ends With a Symbol
The anchor \b needs a word character on one side. In “I like C++ code”, the “+” and the space after it are both non-word characters, so there is no boundary after “C++” and \bC\+\+\b fails. Lookaround asserts “no word character before or after” and works for any first and last character.
boolean withB = Pattern.compile("\\bC\\+\\+\\b").matcher("I like C++ code").find(); // false
boolean lookaround = Pattern.compile("(?<!\\w)C\\+\\+(?!\\w)").matcher("I like C++ code").find(); // true
boolean version = Pattern.compile("(?<!\\w)C\\+\\+(?!\\w)").matcher("I like C++11").find(); // false
7.3. Using matches() to Search
The method String.matches() tests the whole input, so “the cat”.matches(“\\bcat\\b”) returns false. To search inside a text, we use Matcher.find().
boolean whole = "the cat".matches("\\bcat\\b"); // false
boolean found = Pattern.compile("\\bcat\\b").matcher("the cat").find(); // true
The article on matching an exact word builds whole-word search on top of find(), including words taken from user input.
8. The \G Anchor That Continues From the Last Match
The anchor \G matches where the previous match ended, or at the start of the input for the first search. Each new match must start right where the last one stopped, so the search ends at the first gap.
List<String> chained = findAll("\\G\\d", "123abc456"); // [1, 2, 3]
List<String> allDigits = findAll("\\d", "123abc456"); // [1, 2, 3, 4, 5, 6]
List<String> dogs = findAll("\\Gdog", "dog dog"); // [dog]
In the last line, the space breaks the chain, so the second “dog” is not found. We use \G in tokenizers that read a string piece by piece and must reject anything between the pieces, for example a parser for a compact “2h30m15s” duration where a stray letter must stop the parse.
9. Word Boundary Code and Tests
The word boundary project on GitHub runs every pattern from this article and prints the result, and its JUnit 6 tests assert each one. It builds with Maven on Java 25.
mvn -q compile exec:java
mvn test
10. Word Boundary FAQs
Developers ask these questions in searches and forum threads about word boundaries in Java.
10.1. Is “_” a Word Character in Java Regex?
Yes. The class \w is [a-zA-Z_0-9], so “user_1” is one word and \b finds no boundary around the “_”. A hyphen, an apostrophe and a dot are not word characters.
10.2. What Does [\b] Mean in a Java Regex?
Nothing, because Java rejects it. In JavaScript, Python and PCRE, [\b] inside square brackets means the backspace character, but Java throws a PatternSyntaxException for \b inside a character class. To match a backspace in Java, we write \x08, and the word boundary \b always stays outside the brackets.
Pattern inClass = Pattern.compile("[\\b]"); // PatternSyntaxException: Illegal/unsupported escape sequence
boolean backspace = Pattern.matches("[\\x08]", "\b"); // true
10.3. How Do We Match a Whole Word and Ignore Case?
We put \b on both sides of the word and add the flag (?i) or Pattern.CASE_INSENSITIVE. For text with accented letters, we also add (?U), which turns on Unicode word characters and Unicode case folding together.
boolean anyCase = Pattern.compile("(?i)\\bcat\\b").matcher("The CAT sat").find(); // true
10.4. Which Other Boundary Anchors Does Java Support?
Java has nine boundary matchers. All of them match a position and consume no characters.
| Anchor | Matches at |
|---|---|
| ^ | The start of the input, or of each line in MULTILINE mode |
| $ | The end of the input or before a final line terminator, or the end of each line in MULTILINE mode |
| \b | A word boundary |
| \B | A non-word boundary |
| \A | The start of the input, in any mode |
| \G | The end of the previous match |
| \Z | The end of the input, but before a final line terminator |
| \z | The end of the input |
| \b{g} | A Unicode grapheme cluster boundary |
The Java regex metacharacters article lists the other classes and quantifiers used here.
11. Conclusion
The anchor \b marks the edge between a word character and anything else, which makes it the tool for whole words, prefixes such as \bun\w* and suffixes such as \w+ing\b. Combined with ^, $ and MULTILINE, it selects lines that begin or end with a given word.
In Java code, we write it as “\\b”, add (?U) for non-English text, and switch to lookaround when the word starts or ends with a symbol or a hyphen counts as part of the word.
12. References
- Pattern boundary matchers (Java SE 25 API)
- Boundary Matchers (The Java Tutorials)
- JDK-8264160: Regex \b is not consistent with \w
- Word Boundaries (regular-expressions.info)
Happy Learning !!
I have a doubt. Imagine, In a file, if i want all the data that start in a String and ends whit another string, what can i do ?
Thank you