Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AND operator in regular expressions

Tags:

java

regex

I've searched for a while how to use logical operation AND in regular expressions in Java, and have failed.
I've tried to do as recommended in similar topic:

(?=match this expression)(?=match this too)(?=oh, and this)

and it doesn't work. Even simple examples with ?= returns false:

String b = "aaadcd";
System.out.println(b.matches("(?=aa.*)"));

Also I've read that (expression X)(expression Y) should work like X AND Y, but it works like X OR Y.
What am I doing wrong?

Added: Tried to add .* in the end. Still don't work.
For a example:

[2-9]?[0-9]{5,9}||1[2-9][0-9]{1,2}||120[0-9]{1,1}||119[0-9] = X - return false if number is less than 1190

[0-9]{1,3}||1[0-0][0-9]{1,2}||11[0-8][0-9]{1,1}||119[0-2] = Y - return false if number is greater than 1992.

String a = "1189";
a.matches(X) // return false
a.mathes(Y)  // return true
a.matches((?=X)(?=Y).*) // return true, but should return false.

Added: Yep, my regexp is not correct. My bad. The problem solved. Thank everyone very much!

like image 781
Mikhail Avatar asked May 31 '11 09:05

Mikhail


3 Answers

I think what you need is (?=X)Y

  • (?=X) matches X, without consuming it (zero-width)
  • Y and matches Y

The main problem: X and Y are wrong, they should be (assuming 4 digits):

X: 119[0-9]|1[2-9][0-9]{2}|[2-9][0-9]{3}

  • 1190-1199, or
  • 1200-1999, or
  • 2000-9999

Y: 1[0-8][0-9]{2}|19[0-8][0-9]|199[0-2]

  • 1000-1899, or
  • 1900-1980, or
  • 1990-1992

Here a test code:

// X - return false if number is less than 1190
String X = "119[0-9]|1[2-9][0-9]{2}|[2-9][0-9]{3}"; 

// Y - return false if number is greater than 1992.
String Y = "1[0-8][0-9]{2}|19[0-8][0-9]|199[0-2]";

String pattern = "(?=" + X + ")" + Y;

String values = "1000 1100 1180 1189 1190 1191 1199 1200 1290 1900 1980 1989 " +
                "1990 1991 1992 1993 1999 2000 3000 2991 9999";
for (String string : values.split(" ")) {
    System.out.printf("\"%s\" %s%n", string, string.matches(pattern));
}
like image 155
user85421 Avatar answered Sep 29 '22 19:09

user85421


(?= does work.

What you're doing wrong is that you're using matches but your regex doesn't match anything.

(?= is a zero-width positive look-ahead: it doesn't "consume" any characters, but just verifies that its position is followed by something that matches its content.

So either replace your matches() call with Matcher.find() or make sure that your have something in your regex that matches the entire string (.* is a common candidate).

like image 31
Joachim Sauer Avatar answered Sep 29 '22 18:09

Joachim Sauer


As Joachim answered, add a .* in the end:

String b = "aaadcd";
System.out.println(b.matches("(?=aaa)(?=.*dcd).*"));
// => true

String b = "aaaxxx";
System.out.println(b.matches("(?=aaa)(?=.*dcd).*"));
// => false
like image 37
morja Avatar answered Sep 29 '22 18:09

morja