Regex Min and Max Length in Java: {min,max} Explained

Check regex min and max length in Java with {min,max} and anchors, limit characters too, handle line breaks, lookaheads, emoji and the {,n} trap.

A length scale from 0 to 12 characters with the accepted range of the regex ^.{3,10}$ highlighted from 3 to 10, and the four quantifier forms {n}, {n,}, {min,max} and {0,max}

To check the minimum and maximum length of input with a regex, we use the quantifier {min,max} between anchors, so ^.{3,10}$ matches any text of 3 to 10 characters. The dot stands for “any character”, and the quantifier says how many times it may repeat. Replacing the dot with a character class, as in ^[A-Z]{1,10}$, limits both the length and the allowed characters in one pattern.

We use regex length checks for form fields such as user names, PIN codes and display names, and wherever a rule must be stored as text, such as a configuration file or an HTML pattern attribute. The following example runs each length rule as one matches() call.

boolean inRange = "hello".matches("^.{3,10}$");                  // true
boolean tooShort = "hi".matches("^.{3,10}$");                    // false
boolean exactly5 = "hello".matches("^.{5}$");                    // true
boolean atLeast3 = "hello".matches("^.{3,}$");                   // true
boolean emptyOk = "".matches("^.{0,10}$");                       // true

boolean upper = "LOKESH".matches("^[A-Z]{1,10}$");               // true
boolean twoLines = "hello\nworld".matches("^.{1,20}$");          // false, the dot skips \n
boolean dotAll = "hello\nworld".matches("(?s)^.{1,20}$");        // true

Pattern username = Pattern.compile("^(?=.{3,16}$)[a-zA-Z][a-zA-Z0-9_]*$");
boolean validName = username.matcher("lokesh_42").matches();     // true

Notice that a line break makes a short text fail until we add (?s). We cover the four quantifier forms, length plus allowed characters, multi-line input, a total length on a pattern with structure, counting only non-whitespace characters, what “one character” means for emoji and accented letters, and the cases where String.length() is the better tool.

1. The Four Length Quantifiers

In Java regular expressions, a quantifier in curly braces repeats the item before it. It has four forms, and each one maps to a common length rule.

A length scale from 0 to 12 characters with the accepted range of the regex ^.{3,10}$ highlighted from 3 to 10, and the four quantifier forms {n}, {n,}, {min,max} and {0,max}
Between the anchors, the quantifier decides which total lengths pass
RegexLength rule“”“hi”“hello”“hello world”
^.{5}$5, no more and no lessfalsefalsetruefalse
^.{3,}$At least 3falsefalsetruetrue
^.{3,10}$3 to 10falsefalsetruefalse
^.{0,10}$At most 10, empty allowedtruetruetruefalse
^.{1,10}$At most 10, not emptyfalsetruetruefalse

Java does not accept {,10}. A maximum without a minimum is written {0,10}, and the short form throws a PatternSyntaxException when the pattern is compiled.

Pattern noMin = Pattern.compile("^.{,10}$");      // PatternSyntaxException: Illegal repetition near index 3
Pattern zeroMin = Pattern.compile("^.{0,10}$");
boolean fits = zeroMin.matcher("hello").matches();   // true

The anchors ^ and $ are what make the quantifier a length check. Without them, find() succeeds on any input that contains 3 characters somewhere, whatever its total length. With String.matches() the whole input must match anyway, but we keep the anchors so the pattern also works with find() and in other tools. The article on start and end of string explains the anchors in detail.

boolean unanchored = Pattern.compile(".{3,10}").matcher("hello world, how are you?").find();    // true
boolean anchored = Pattern.compile("^.{3,10}$").matcher("hello world, how are you?").find();    // false

2. Limiting Length and Characters Together

The dot accepts anything. In most fields, we also want to restrict which characters are allowed, and the quantifier applies to that character class.

Pattern upper = Pattern.compile("^[A-Z]{1,10}$");

boolean name = upper.matcher("LOKESH").matches();                // true
boolean nine = upper.matcher("JAVACRAZY").matches();             // true
boolean sixteen = upper.matcher("LOKESHGUPTAINDIA").matches();   // false, 16 letters
boolean digits = upper.matcher("LOKESH123").matches();           // false
boolean lower = upper.matcher("lokesh").matches();               // false
boolean empty = upper.matcher("").matches();                     // false

Other classes work the same way, for example ^\d{4,6}$ for a 4- to 6-digit PIN and ^[a-zA-Z0-9]{8,32}$ for an alphanumeric code. The alphanumeric regex article has more variations.

A banking app shows the typical use. The PIN field must hold 4 to 6 digits, so ^\d{4,6}$ rejects “12a4” and “1234567” in one check, and the error message can name both rules.

3. Input With Line Breaks

The dot does not match line terminators such as \n. A comment or address field with two lines fails ^.{1,20}$ even when it is short. Two fixes make the dot count line breaks too.

  • The inline flag (?s) at the start of the pattern, or the Pattern.DOTALL flag in Pattern.compile(), lets the dot match line terminators.
  • The class [\s\S] in place of the dot matches any character, including line breaks.
boolean plainDot = "hello\nworld".matches("^.{1,20}$");          // false
boolean dotAll = "hello\nworld".matches("(?s)^.{1,20}$");        // true
boolean anyChar = "hello\nworld".matches("^[\\s\\S]{1,20}$");    // true

A second detail matters when we use find() instead of matches(). In Java, $ also matches right before a final line terminator, so a trailing \n slips through. The anchor \z means “the very end of the input” and has no such exception.

boolean viaMatches = "hello\n".matches("^.{1,10}$");                       // false
boolean viaFind = Pattern.compile("^.{1,10}$").matcher("hello\n").find();  // true
boolean withZ = Pattern.compile("^.{1,10}\\z").matcher("hello\n").find();  // false

4. Length as One Rule Among Several

Sometimes the characters follow a structure, and a single quantifier cannot cover the total length. A user name that must start with a letter and continue with letters, digits or “_” is [a-zA-Z][a-zA-Z0-9_]*. Its length is “1 plus whatever * matched”, which no quantifier on one part can limit.

A lookahead solves the problem. The group (?=.{3,16}$) checks at the start that the whole input has 3 to 16 characters, without consuming any of them. The main pattern checks the structure from the same position.

Pattern username = Pattern.compile("^(?=.{3,16}$)[a-zA-Z][a-zA-Z0-9_]*$");

boolean valid = username.matcher("lokesh_42").matches();             // true
boolean three = username.matcher("abc").matches();                   // true
boolean two = username.matcher("lo").matches();                      // false, too short
boolean seventeen = username.matcher("lokesh_gupta_2026").matches(); // false, 17 characters
boolean digitFirst = username.matcher("42lokesh").matches();         // false
boolean hyphen = username.matcher("lokesh-42").matches();            // false

The $ inside the lookahead is required, because (?=.{3,16}) without it only checks that at least 3 characters exist. The same technique limits the local part of an address in the Java email validation regex article, and the password validator article stacks several lookaheads in front of one length check.

5. Counting Only Non-Whitespace Characters

A rule like “at least 5 real characters” should not count spaces. The pattern ^\s*(?:\S\s*){5,10}$ repeats a group of “one non-whitespace character followed by any whitespace”, so the quantifier counts only the non-whitespace characters.

Pattern nonSpace = Pattern.compile("^\\s*(?:\\S\\s*){5,10}$");

boolean word = nonSpace.matcher("hello").matches();              // true
boolean spaced = nonSpace.matcher("h e l l o").matches();        // true
boolean padded = nonSpace.matcher("  hello  ").matches();        // true
boolean two = nonSpace.matcher("hello world").matches();         // true, 10 letters
boolean shortOne = nonSpace.matcher("hi").matches();             // false

The group (?:…) is a non-capturing group, which groups the two items for the quantifier without storing what they matched. A product review form uses this rule to reject ” ok “, which has 12 characters but only 2 real ones. The same idea counts words, and the article on limiting the number of words shows it.

6. What Counts as One Character

Java strings store text as UTF-16 char values, and some characters need two of them. The regex dot works on code points (Unicode characters), so its count can differ from String.length(). What a user sees as one character can even be two code points, so text has three different lengths.

  • The method length() counts UTF-16 char values.
  • The dot and codePointCount() count code points.
  • The escape \X counts grapheme clusters, the characters a user sees on screen.

Two inputs show the difference. A flag emoji is two code points (two “regional indicator” symbols) and four char values. The word “cafe” with a combining accent on the last “e” (U+0301) has 5 char values and 5 code points but shows as 4 characters.

String flag = "\uD83C\uDDEE\uD83C\uDDF3";      // the flag of India
String combining = "cafe\u0301";               // "cafe" with a combining accent

int flagChars = flag.length();                                  // 4
int flagCodePoints = flag.codePointCount(0, flag.length());     // 2
boolean twoDots = flag.matches(".{2}");                         // true
boolean oneGrapheme = flag.matches("\\X");                      // true

int combiningChars = combining.length();                        // 5
boolean fourDots = combining.matches("^.{4}$");                 // false
boolean fourGraphemes = combining.matches("^\\X{4}$");          // true

For a limit that users see, such as “at most 5 characters” in a display name, we use \X instead of the dot. For a limit that protects storage, such as a database column, we count the way the column counts, which is characters or bytes depending on the database and column type.

7. Building the Pattern From Settings

When the limits come from configuration, we build the pattern string from the two numbers. Checking the range first gives a clear error message instead of a regex syntax error.

static Pattern lengthPattern(int min, int max) {
    if (min < 0 || max < min) {
        throw new IllegalArgumentException("invalid range " + min + ".." + max);
    }
    return Pattern.compile("^.{" + min + "," + max + "}$", Pattern.DOTALL);
}
Pattern twoToFour = lengthPattern(2, 4);
String source = twoToFour.pattern();                         // "^.{2,4}$"
boolean three = twoToFour.matcher("abc").matches();          // true
boolean five = twoToFour.matcher("abcde").matches();         // false
Pattern reversed = lengthPattern(10, 1);                     // IllegalArgumentException: invalid range 10..1

Without the range check, a reversed range reaches the regex engine, which throws a PatternSyntaxException when the pattern is compiled.

Pattern raw = Pattern.compile("^.{10,1}$");      // PatternSyntaxException: Illegal repetition range near index 7

8. When String.length() Is the Better Choice

A regex is the right tool when length is one of several rules in the same pattern, when the rule must be stored as text (a configuration file, an HTML pattern attribute, a JSON schema), or when the same pattern runs in the browser and on the server. For a plain length check in Java code, a method call is shorter and clearer.

static boolean hasLength(String s, int min, int max) {
    if (s == null) {
        return false;
    }
    int n = s.codePointCount(0, s.length());
    return n >= min && n <= max;
}
boolean okLength = hasLength("hello", 3, 10);          // true
boolean nullText = hasLength(null, 3, 10);             // false

The method hasLength() counts code points, like the regex dot. We use s.length() instead if the limit is in UTF-16 units.

9. Running the Length Examples

The GitHub project prints every result in this article, including the quantifier table, the line-break cases and the Unicode counts. The JUnit 6 tests assert each value and the PatternSyntaxException details. To run it, we need Java 25 and Maven.

mvn -q compile exec:java
mvn test

10. Regex Length FAQs

Readers ask these questions when a length regex does not behave as expected.

10.1. Does Java Support {,max} Without a Minimum?

No. Java throws PatternSyntaxException: Illegal repetition for {,10}, as shown in section 1. We write {0,10} for “at most 10”.

10.2. Why Does the Length Regex Accept Longer Text?

The pattern has no anchors and runs with find(), which succeeds as soon as any part of the text has the right length. We add ^ and $ (or \z), or we call matches(), which always tests the whole input.

10.3. How Do We Limit a Number Value Instead of Its Length?

We parse it. The regex ^\d{1,3}$ limits a number to three digits, but a rule like “1 to 100” is a range of values, which a regex can express only with clumsy alternations. We check the shape with the regex, parse with Integer.parseInt(), and compare the result.

String qty = "250";
boolean shapeOk = qty.matches("^\\d{1,3}$");                                // true
boolean inRange = shapeOk && Integer.parseInt(qty) >= 1 && Integer.parseInt(qty) <= 100;   // false

10.4. Does the Length Count Change With Emoji?

Yes. String.length() counts an emoji such as a flag as 4, the dot counts it as 2, and \X counts it as 1. We pick the count that matches the limit we enforce, as section 6 explains.

11. Conclusion

A length check in a regex is a quantifier between anchors, ^.{min,max}$, with {n}, {n,} and {0,n} for exact, minimum and maximum lengths. A character class in place of the dot limits the characters too, (?s) counts line breaks, and a lookahead such as (?=.{3,16}$) adds a total length to a pattern with structure.

For user-visible limits we count graphemes with \X, and for a single plain length rule, codePointCount() or length() is the simpler choice.

12. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. Hello Friend
    need one help, I am using this ^([a-zA-Z][a-zA-Z0-9_]*){8,30}$
    I am matching with SushanT007 and getting false
    Its picking 8 chanracter. I want to it will pickup both character and number
    could you please help here

Comments are closed.

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.