Regex End of Line and Start of Line in Java (^, $)

How the regex anchors ^ and $ match the start and end of a string or of each line in Java, plus \A, \z, \Z, MULTILINE and Windows line breaks.

Java regex

To match the end of a line in a regex, we use the dollar sign $, and to match the start of a line, we use the caret ^. Both are anchors: they match a position in the text, not a character. By default they match only at the start and the end of the whole string. With the MULTILINE flag, or (?m) inside the pattern, they also match at the start and end of every line.

This article shows how to check that a Java string starts or ends with a pattern, how to match each line of a multi-line text, and when to use \A, \z and \Z instead of ^ and $. It also explains two details that cause real bugs: $ also matches before a final line break, and Windows line breaks are two characters long.

Each row of the table has its own section after the quick reference.

To matchRegexJava string literal
“The” at the start of the string^The“^The”
“ing” at the end of the stringing$“ing$”
A whole string of letters^[a-z]+$“^[a-z]+$”
A word at the start of any line(?m)^\w+“(?m)^\\w+”
The very end of the input\z“\\z”
Any line break (\n, \r\n, \r)\R“\\R”
Pattern.compile("^The").matcher("The sun is shining").find();     // true
Pattern.compile("ing$").matcher("The sun is shining").find();     // true
Pattern.compile("^sun").matcher("The sun is shining").find();     // false

String fruits = "apple\nbanana\ncherry";
Pattern.compile("^banana$").matcher(fruits).find();                       // false
Pattern.compile("^banana$", Pattern.MULTILINE).matcher(fruits).find();    // true
Pattern.compile("(?m)^\\w+").matcher(fruits).results()
    .map(MatchResult::group).toList();                                    // [apple, banana, cherry]

Pattern.compile("cat$").matcher("cat\n").find();      // true, $ matches before a final "\n"
Pattern.compile("cat\\z").matcher("cat\n").find();    // false
"a\r\nb\nc".split("\\R");                              // [a, b, c]

1. Anchors Have Zero Width

An anchor checks where the regex engine is, and it consumes no characters. The match of a lone ^ or $ is an empty string. Inserting text at the anchor position shows this clearly: replaceAll() puts the replacement at the position, and no character of the input is removed.

"cat".replaceAll("^", ">");      // ">cat"
"cat".replaceAll("$", "!");      // "cat!"

Matcher end = Pattern.compile("$").matcher("cat");
end.find();                      // true
end.start();                     // 3, the position after "t"
end.group();                     // "", an empty match

Because anchors have zero width, ^The matches the same three characters as The. The anchor only adds a condition: there must be nothing before “The”.

2. Regex for “Starts With”: the Caret ^

A caret at the beginning of a pattern makes the match start at position 0. We use it with Matcher.find(), which searches the input, so the rest of the string can contain anything.

The string starts withRegexJava string literal
A digit^\d“^\\d”
An ASCII letter^[a-zA-Z]“^[a-zA-Z]”
The word “Hello”^Hello“^Hello”
A character that is not a letter or digit^[^a-zA-Z0-9]“^[^a-zA-Z0-9]”
“hello” in any case(?i)^hello“(?i)^hello”
Pattern.compile("^\\d").matcher("1st place").find();            // true
Pattern.compile("^[a-zA-Z]").matcher("Lokesh").find();          // true
Pattern.compile("^Hello").matcher("Hello world").find();        // true
Pattern.compile("^Hello").matcher("Say Hello").find();          // false
Pattern.compile("^[^a-zA-Z0-9]").matcher("#tag").find();        // true
Pattern.compile("(?i)^hello").matcher("HELLO there").find();    // true

The caret has a second meaning: right after an opening bracket, it negates a character class. In ^[^a-zA-Z0-9], the first caret is the anchor and the second one means “not”.

When the prefix is fixed text, String.startsWith() is clearer and faster than a regex. The regex version is worth it only when the start is a pattern, such as “a digit” or “one of several words”.

"Hello world".startsWith("Hello");      // true

3. Regex for “Ends With”: the Dollar Sign $

A dollar sign at the end of a pattern makes the match end at the last position of the input. The checks mirror the “starts with” cases:

Pattern.compile("\\d$").matcher("order 42").find();              // true
Pattern.compile("world$").matcher("Hello world").find();         // true
Pattern.compile("world$").matcher("world peace").find();         // false
Pattern.compile("[.!?]$").matcher("Done!").find();               // true
Pattern.compile("\\.(jpg|png)$").matcher("photo.png").find();    // true
Pattern.compile("\\.(jpg|png)$").matcher("photo.png.txt").find();   // false

The file extension check shows why the anchor matters. Without the $, the pattern \.(jpg|png) also finds “.png” inside “photo.png.txt”. For one fixed suffix, String.endsWith() does the same job: “photo.png”.endsWith(“.png”) returns true.

4. Matching the Whole String With ^ and $

With both anchors, the pattern must cover the input from the first character to the last. This is how we validate a value with find(): without anchors, find() accepts any input that merely contains a match.

Pattern.compile("[a-z]+").matcher("abc123").find();      // true, "abc" is found
Pattern.compile("^[a-z]+$").matcher("abc123").find();    // false
Pattern.compile("^g.*g$").matcher("gang").find();        // true
Pattern.compile("^$").matcher("").find();                // true, an empty string

"abc".matches("[a-z]+");                                 // true

String.matches() and Matcher.matches() already require the whole input to match, so ^ and $ add nothing there. With matches(), we leave out the anchors; with find(), we add them. The article Regex for alphanumeric characters uses this for input validation.

5. Matching Every Line With MULTILINE

When the input has several lines, ^ and $ still match only at the start and end of the whole text. The Pattern.MULTILINE flag changes that: ^ then also matches right after each line break, and $ right before each line break. The inline form of the flag is (?m).

The text apple, line break, banana, line break, cherry, with caret and dollar positions marked once for the whole string in default mode and at every line in MULTILINE mode
In default mode, ^ and $ match once each; with MULTILINE, they match at the start and end of every line.

A Java text block is a convenient way to write multi-line input. The closing quotes on the last line mean the text has no final line break.

String sentences = """
    The sun is shining
    Apples are delicious
    The moon is bright
    Birds are singing""";

Pattern.compile("^The.*", Pattern.MULTILINE).matcher(sentences).results()
    .map(MatchResult::group).toList();
// [The sun is shining, The moon is bright]

Pattern.compile("(?m)^.*ing$").matcher(sentences).results()
    .map(MatchResult::group).toList();
// [The sun is shining, Birds are singing]

Pattern.compile("^.*ing$").matcher(sentences).results()
    .map(MatchResult::group).toList();
// [], no MULTILINE: ^ is only at "The sun", and .* stops at the first line break

The pattern ^.*ing$ works line by line because the dot does not match a line break, so .* cannot run into the next line. If the pattern also uses DOTALL, the dot crosses lines and the result changes.

For simple line filters, the String.lines() method is often easier to read than a MULTILINE regex:

sentences.lines().filter(line -> line.startsWith("The")).toList();
// [The sun is shining, The moon is bright]

6. The Trailing Line Break Trap

In Java, $ matches at the end of the input and also right before a line break at the very end. This rule exists so that a line read with its “\n” still matches word$. It confuses many developers, because the line break is not part of the match.

Pattern.compile("cat$").matcher("cat\n").find();      // true
"cat\n".matches("cat$");                              // false, nothing matches the "\n"

"a\nb\n".replaceAll("$", "!");                         // "a\nb!\n!"
"a\nb\n".replaceAll("(?m)$", "!");                     // "a!\nb!\n!"
"a\nb\n".replaceAll("(?m)^", "> ");                    // "> a\n> b\n"

The third line shows the rule at work: without MULTILINE, $ still matches twice, once before the final “\n” and once at the very end. The last line shows a related rule: in MULTILINE mode, ^ does not match after a line break that ends the input, so no “> ” is added at the end.

The trap matters for validation. A check written as ^\d+$ with find() accepts “123\n”, a value with a hidden line break. The next section shows the fix.

7. \A, \z and \Z: Anchors for the Whole Input

Java has three anchors that ignore the MULTILINE flag. They always refer to the whole input:

AnchorMatches atWith a final line break “abc\n”
^Start of input; start of each line in MULTILINEBefore “a”
$End of input or before a final line break; end of each line in MULTILINEBefore and after “\n”
\AStart of input onlyBefore “a”
\ZEnd of input, or before a final line breakBefore and after “\n”
\zThe absolute end of input onlyAfter “\n” only
String fruits = "apple\nbanana\ncherry";
Pattern.compile("(?m)^banana").matcher(fruits).find();      // true
Pattern.compile("(?m)\\Abanana").matcher(fruits).find();    // false
Pattern.compile("(?m)apple$").matcher(fruits).find();       // true
Pattern.compile("(?m)apple\\z").matcher(fruits).find();     // false

Pattern.compile("cat\\Z").matcher("cat\n").find();          // true
Pattern.compile("cat\\z").matcher("cat\n").find();          // false

For strict validation with find(), we use \A and \z, or we call matches() instead. Both reject a value with a trailing line break:

Pattern.compile("^\\d+$").matcher("123\n").find();        // true, the "\n" slips through
Pattern.compile("\\A\\d+\\z").matcher("123\n").find();    // false
"123\n".matches("\\d+");                                  // false

8. Windows Line Breaks and \R

Text from files and HTTP requests often uses the Windows line break \r\n, which is two characters. Java handles it correctly in MULTILINE mode: $ matches before the \r, not between \r and \n. The line terminators that Java recognizes for ^ and $ are:

  • \n (line feed, Unix and macOS)
  • \r\n (carriage return plus line feed, Windows)
  • \r (carriage return alone, old Mac files)
  • \u0085, \u2028 and \u2029 (Unicode next line, line separator and paragraph separator)

The UNIX_LINES flag, inline (?d), limits the list to \n only. With it, a \r before the \n becomes part of the line, so cat$ no longer matches “cat\r\n”.

Pattern.compile("(?m)cat$").matcher("cat\r\ndog").find();       // true
Pattern.compile("(?md)cat$").matcher("cat\r\ndog").find();      // false, UNIX_LINES
Pattern.compile("(?m)^dog").matcher("cat\u2028dog").find();     // true

"a\r\nb\nc\rd".split("\\R");     // [a, b, c, d]
"a\r\nb".split("\n");            // ["a\r", "b"], the "\r" stays behind

To split text into lines or to match “a line break” inside a pattern, we use \R. It matches any of the line breaks above as one unit, plus vertical tab and form feed, and it never splits a \r\n pair. Splitting on “\n” alone leaves a stray \r at the end of each line of a Windows file.

9. The Example Project on GitHub

The anchors example on GitHub prints the result of every snippet above, and its JUnit 6 tests check each one, including the trailing line break cases. The project builds with Maven on Java 25.

mvn -q compile exec:java
mvn test

10. Conclusion

The caret ^ anchors a pattern to the start of a string and the dollar sign $ anchors it to the end. With MULTILINE or (?m), both also match at every line, which is how we search a multi-line text line by line. For validation, matches() or the pair \A and \z is safer than ^ and $, because $ accepts a trailing line break. When we only need a fixed prefix or suffix, startsWith() and endsWith() are the simpler choice. The Java regex metacharacters reference lists the other anchors, such as the word boundary \b.

11. References

The boundary matchers and the line terminator rules are defined in the “Line terminators” and “Boundary matchers” parts of the Pattern JavaDoc.

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.