15

I'd like to test if a string ends with a a digit. I expect the following Java line to print true. Why does it print false?

System.out.println("I end with a number 4".matches("\\d$"));
javanna
  • 59,145
  • 14
  • 144
  • 125
Thor
  • 600
  • 1
  • 6
  • 17
  • This may also be related to your question: http://stackoverflow.com/questions/627545/java-regexp-problem-www-vs-www – AdrianoKF Oct 07 '11 at 16:52

5 Answers5

15

Your regex will not match the entire string but only the last part. Try the below code and it should work fine as it matches the entire string.

System.out.println("I end with a number 4".matches("^.+?\\d$"));

You can test this for a quick check on online regex testers like this one: http://www.regexplanet.com/simple/index.html. This also gives you what you should use in the Java code in the results with appropriate escapes.

The .+ will ensure that there is atleast one character before the digit. The ? will ensure it does a lazy match instead of a greedy match.

Kash
  • 8,799
  • 4
  • 29
  • 48
  • There's no point doing a lazy match in this case. We *want* the `.+` to gobble up the whole string right away. Then it will back off one position to compare the last character to `\d`, which is the only thing we care about. – Alan Moore Oct 07 '11 at 22:58
10

In Java Regex, there's a difference between Matcher.find() (find a match anywhere in the String) and Matcher.matches() (match the entire String).

String only has a matches() method (implemented equivalent to this code:Pattern.compile(pattern).matcher(this).matches();), so you need to create a pattern that matches the full String:

System.out.println("I end with a number 4".matches("^.*\\d$"));
Carlos Robles
  • 10,828
  • 3
  • 41
  • 60
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • Actually, more simply: System.out.println("I end with a number 4".matches(".*\\d")); but the '$' should mean I don't have to specify .* at the beginning. Why doesn't '$' at the end work? – Thor Oct 07 '11 at 16:50
  • The extra backspace removes the escape behaviour. Hence "^.*\\d$" may not work. You can test this in online regex testers like this: http://www.regexplanet.com/simple/index.html – Kash Oct 07 '11 at 16:51
  • @Kash in Java, the extra backspace is necessary – Sean Patrick Floyd Oct 07 '11 at 16:55
  • 2
    @Thor both the `^` and the `$` are entirely optional when doing full matches. They have no effect whatsoever and are only there for clarity – Sean Patrick Floyd Oct 07 '11 at 16:57
  • @Sean, you are right, there is no verbatim in Java like C# has @. My bad. – Kash Oct 07 '11 at 16:59
  • @ Sean, Although the .* will also match a single digit and not necessarily a string that ends in a digit. So you may wanna try .+ instead to ensure there is atleast one char before the number – Kash Oct 07 '11 at 17:02
  • @Kash true, but that's not the OP's requirement. He wanted to test if the String ends with a digit and nothing else. – Sean Patrick Floyd Oct 07 '11 at 17:08
  • `^` and the `$` are entirely optional ... I'd rephrase that to be you have to have both or neither, but it is the same in either case. Thanks for clarifying. – Thor Oct 07 '11 at 17:22
  • Yes, I was looking for anything that ends with (not something followed by a digit). `.*` not `.+` – Thor Oct 07 '11 at 17:24
  • FYI: Matcher.find is the behavior I'm looking for: `System.out.println(Pattern.compile("\\d$").matcher("I end with a number 4").find());` – Thor Oct 07 '11 at 17:30
  • @Thor .+ in this context will also give you anything that ends with a digit AND ensures that there is atleast one char before the digit. For example, if you have a string that has only a digit like "4" and nothing before 4, then .* will match this string and .+ will not. Whereas your string "I end with a number 4" will be matched by both .* and .+ – Kash Oct 07 '11 at 18:11
2

Your RegEx expression is slightly off. Try this:

System.out.println("I end with a number 4".matches("^.*\\d$"));

You can also simply test like this if you are evaluating a line at a time:

System.out.println("I end with a number 4".matches(".*\\d"));

Your original expression, without .* only tested to see whether the string was a number and did not account for text that may precede that number. That's why it was always false.

The following does evaluate to true:

System.out.println("4".matches("^\\d$"));
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
0
System.out.println("I end with a number 4".matches(".*\\d")); // prints true

or

String s = "I end with a number 4";
System.out.println(Character.isDigit(s.charAt(s.length()-1)));  // prints true
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
-2

try this:

System.out.println("I end with a number 4".matches(".*\\d\$"));
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97