3

I am creating a regular expression to evaluate if an IP address is a valid multicast address. This validation is occurring in real time while you type (if you type an invalid / out of range character it is not accepted) so I cannot simply evaluate the end result against the regex. The problem I am having with it is that it allows for a double period after each group of numbers (224.. , 224.0.., 224.0.0.. all show as valid).

The code below is a static representation of what's happening. Somehow 224.. is showing as a legal value. I've tested this regex online (non-java'ized: ^2(2[4-9]|3\d)(.(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$ ) and it works perfectly and does not accept the invalid input i'm describing.

Pattern p = Pattern.compile("^2(2[4-9]|3\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
Matcher m = p.matcher("224..");


if (!m.matches() && !m.hitEnd()) {
    System.out.println("Invalid");
} else {
    System.out.println("Valid");
}

It seems that the method m.hitEnd() is evaluating to true whenever I input 224.. which does not make sense to me. If someone could please look this over and make sure I'm not making any obvious mistake and maybe explain why hitEnd() is returning true in this case I'd appreciate it. Thanks everyone.

dymmeh
  • 22,247
  • 5
  • 53
  • 60
  • First, `m.matches()` always matches the complete input, so you don't need to start your expression with `^`. Next, `m.hitEnd()` indicates that regexp engine hit the end of input, which not necessarily means that your regexp matched till the end of input. – dma_k Aug 16 '11 at 22:05
  • The following question seems to suggest otherwise http://stackoverflow.com/questions/2469231/how-can-i-perform-a-partial-match-with-java-util-regex – Justin Breitfeller Aug 17 '11 at 00:38
  • @dma_k: `hitEnd()` means the regex *was* matching, but it ran out of input; with more input, it's possible a match could be achieved (or, if it did match, it's possible a *longer* match could be achieved). It's similar to [partial matching](http://www.boost.org/doc/libs/1_34_1/libs/regex/doc/partial_matches.html) in Boost.Regex. – Alan Moore Aug 17 '11 at 04:44

4 Answers4

4

After doing some evaluating myself (after discovering this was on Android), I realized that the same code responds differently on Dalvik than it does on a regular JVM.

The code is:

   Pattern p = Pattern.compile("^2(2[4-9]|3\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
    Matcher m = p.matcher("224..");

    if (!m.matches() && !m.hitEnd()) {
        System.out.println("Invalid");
    } else {
        System.out.println("Valid");
    }

This code (albeit modified a bit), prints Valid on Android and Invalid on the JVM.

Justin Breitfeller
  • 13,737
  • 4
  • 39
  • 47
  • 1
    I have filed an issue at http://code.google.com/p/android/issues/detail?id=19308 to hopefully look into this matter. – Justin Breitfeller Aug 17 '11 at 01:03
  • Verified that this is the bug. That's why everyone else seemed to be getting different results than me since I was running it on Android. – dymmeh Aug 17 '11 at 12:51
1

I do not know how have you tested your regex but it does not look correct according to your description.

Your regext requires all 4 sections of digits. There is no chance it will match 224.. Only [0-1] and \d are marked with question mark and therefore are optional.

So, without dealing with details of limitations of wich specific digits are permitted I'd suggest you something like this:

^\\d{1-3}\\.(\\d{0-3}\\.)?(\\d{0-3}\\.)?(\\d{0-3}\\.)?$

And you do not have to use hitEnd(): $ in the end is enough. And do not use matches(). Use find() instead. matches() is like find() but adds ^ and $ automatically.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • `224.` is not a match, but it's still a *potential* match; that's what `hitEnd()` means. But, add another dot (`224..`), and there's no longer a possibility of a match; `matches()` and `hitEnd()` should both return `false`. But it seems `hitEnd()` is ignoring the second dot. – Alan Moore Aug 17 '11 at 05:28
0

I just tested out your code and m.hitEnd() evaluates to false for me, and I am receiving invalid...

So I'm not really sure what the problem here is?

This 0ne Pr0grammer
  • 2,632
  • 14
  • 57
  • 81
0

I reported bug 20625 in Dalvik. In the interim, you don't need to use hitEnd(), having the $ suffix should be sufficient.

public void testHitEnd() {
  String text = "b";
  String pattern = "^aa$";
  Matcher matcher = Pattern.compile(pattern).matcher(text);
  assertFalse(matcher.matches());
  assertFalse(matcher.hitEnd());
}
Jesse Wilson
  • 39,078
  • 8
  • 121
  • 128