190

I have this small piece of code

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("[a-z]"))
    {
        System.out.println(s);
    }
}

Supposed to print

dkoe

but it prints nothing!!

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
John Eipe
  • 10,922
  • 24
  • 72
  • 114
  • 65
    Java's `matches` puts a ^ at the start and a $ at the end of regexes for you. So `matches("[a-z]")` will actually look for /^[a-z]$/ instead. – Robino Aug 02 '16 at 16:38
  • Yes @Robino you are absolutely right. – Mihir Oct 05 '18 at 07:00
  • 4
    Surely, if you expect `matches` to look for any occurrence of `[a-z]`, then it should match them all? I would not expect `matches` to check each and every character individually against the regex. – PhilHibbs Dec 06 '18 at 15:22
  • @Robino: Where is that functionality described/documented? – Toru Apr 03 '20 at 09:17
  • 3
    @Toru On the java docs page for String.Matches - where else? A casual Google of "java string matches documentation" reveals, in the top result, the phrase "str.matches(regex) yields exactly the same result as the expression". The important word is "exactly". – Robino Apr 04 '20 at 21:10
  • 1
    @PhilHibbs Yes, that was my expectation also! – Robino Apr 04 '20 at 21:11

9 Answers9

404

Welcome to Java's misnamed .matches() method... It tries and matches ALL the input. Unfortunately, other languages have followed suit :(

If you want to see if the regex matches an input text, use a Pattern, a Matcher and the .find() method of the matcher:

Pattern p = Pattern.compile("[a-z]");
Matcher m = p.matcher(inputstring);
if (m.find())
    // match

If what you want is indeed to see if an input only has lowercase letters, you can use .matches(), but you need to match one or more characters: append a + to your character class, as in [a-z]+. Or use ^[a-z]+$ and .find().

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
fge
  • 119,121
  • 33
  • 254
  • 329
  • 3
    i find 100s of incomplete tutorials online. Couldn't find a good one. Do you have any suggestions? – John Eipe Jan 19 '12 at 09:33
  • 1
    Thanx @fge for explain `.matches()`. May be you know why `.find()` works so slow in [this example](http://stackoverflow.com/questions/18603729/matcher-dont-find-on-2nd-step)? – Konstantin Konopko Sep 04 '13 at 19:26
  • 4
    What do you mean by *other languages followed suit*? From what I know, only C++ has an equivalent set of methods - `regex_search` and `regex_match`. In Python, `re.match` only anchors the match at the start of the string (as if it were `\Apattern`) and Python 3.x has got a nice `.fullmatch()` method. In JS, Go, PHP and .NET, the there are no regex methods that anchor the match implicitly. ElasticSearch, XML Schema and HTML5/Validators Angluar patterns are always anchored by default. In Swift/Objective C, there is a way to anchor the pattern at the start with an option. – Wiktor Stribiżew Nov 15 '17 at 09:09
  • 1
    Is there a oneliner way to do this? – Cardinal System Jun 10 '19 at 00:37
  • 4
    That feeling when you waste hours wondering what's wrong with your regex and end up on this SO answer realising that you've already upvoted it long time ago... – matewka Sep 27 '20 at 18:44
  • 2
    It is true String#matches() matches the entire string by default but `"123abc".matches("^[0-9]+.*$")` or `"123abc".matches("[0-9]+.*")` works too – Hariharan Mar 26 '21 at 14:10
51

[a-z] matches a single char between a and z. So, if your string was just "d", for example, then it would have matched and been printed out.

You need to change your regex to [a-z]+ to match one or more chars.

dogbane
  • 266,786
  • 75
  • 396
  • 414
  • 14
    Of course it matches a single char, that's what that regexp does! What isn't clear however (and should not be the case either!) is that java puts the prefix `^` and suffix `$` around the provided regexp, altering it unwantedly and creating weird bugs. They should not do that, because that's not how the initial regexp was meant. – klaar Oct 24 '16 at 14:52
33

String.matches returns whether the whole string matches the regex, not just any substring.

yshavit
  • 42,327
  • 7
  • 87
  • 124
17

java's implementation of regexes try to match the whole string

that's different from perl regexes, which try to find a matching part

if you want to find a string with nothing but lower case characters, use the pattern [a-z]+

if you want to find a string containing at least one lower case character, use the pattern .*[a-z].*

Wim Deblauwe
  • 25,113
  • 20
  • 133
  • 211
Hachi
  • 3,237
  • 1
  • 21
  • 29
  • more info [here](http://alvinalexander.com/blog/post/java/java-pattern-matching-matches-method-not-working) – ycomp Mar 12 '16 at 01:22
  • 3
    Why is this [not documented](https://docs.oracle.com/javase/10/docs/api/java/lang/String.html#matches(java.lang.String))?! – Leo Orientis Jun 22 '18 at 18:30
13

Used

String[] words = {"{apf","hum_","dkoe","12f"};
    for(String s:words)
    {
        if(s.matches("[a-z]+"))
        {
            System.out.println(s);
        }
    }
Boni
  • 590
  • 1
  • 3
  • 11
5

I have faced the same problem once:

Pattern ptr = Pattern.compile("^[a-zA-Z][\\']?[a-zA-Z\\s]+$");

The above failed!

Pattern ptr = Pattern.compile("(^[a-zA-Z][\\']?[a-zA-Z\\s]+$)");

The above worked with pattern within ( and ).

SLePort
  • 15,211
  • 3
  • 34
  • 44
Shanta
  • 51
  • 1
  • 5
2

Your regular expression [a-z] doesn't match dkoe since it only matches Strings of lenght 1. Use something like [a-z]+.

-2

you must put at least a capture () in the pattern to match, and correct pattern like this:

String[] words = {"{apf","hum_","dkoe","12f"};
for(String s:words)
{
    if(s.matches("(^[a-z]+$)"))
    {
        System.out.println(s);
    }
}
MohsenB
  • 1,669
  • 18
  • 29
-3

You can make your pattern case insensitive by doing:

Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE);
Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
Anita Kulkarni
  • 304
  • 1
  • 3
  • 10