flowfree
flowfree

Reputation: 16462

How to match required characters in random order using regular expression?

I need to match text which has @, #, and any number in it. The characters can be in random position as long as they are in the text. Given this input:

abc@#d9
a9b#c@d
@@abc#9
abc9d@@
a#b#c@d

The regex should match the first 3 lines. Currently my regex is:

/@.*?#.*?[0-9]/

Which doesn't work since it will only match the three chars in sequence. How to match the three chars in random order?

Upvotes: 2

Views: 3003

Answers (3)

Eugene Ryabtsev
Eugene Ryabtsev

Reputation: 2301

Decided I better write this as an answer:

$text = "a9b#c@d";
$themAll = "#@";
$themAny = "0123456789";
echo (strspn($themAll, $text)==strlen($themAll) && strpbrk($text, $themAny));

For maintenance and some (limited) extending this should be as easy as it gets, especially whth longer $themAll lists.

Upvotes: 0

Andreas Wong
Andreas Wong

Reputation: 60534

Found one of this ugly regex, if you really must use one:

/(?=.*@)(?=.*#)(?=.*[0-9]).*/

http://jsfiddle.net/BP53f/2/

The regex is basically using what they call lookahead

http://www.regular-expressions.info/lookaround.html

A simple case from the link above is trying to match q, followed by u, by doing q(?=u), that's why it's called lookahead, it finds q followed by u ahead.

Let's take one of your valid case: a9b#c@d

The first lookahead is (?=.*@), which states: Match anything, followed by a @. So it does, which is the string a9b#c, then since the match from the lookahead must be discarded, the engine steps back to the start of the string, which is an a. Then it goes to

(?=.*#), which states: Match anything that is followed by #, then it finds it at a9b. etc. The difference between using lookahead and (a)(b)(c) is basically the stepping back.

From the link above:

Let's take one more look inside, to make sure you understand the implications of the lookahead. Let's apply q(?=u)i to quit. I have made the lookahead positive, and put a token after it. Again, q matches q and u matches u. Again, the match from the lookahead must be discarded, so the engine steps back from i in the string to u. The lookahead was successful, so the engine continues with i. But i cannot match u. So this match attempt fails. All remaining attempts will fail as well, because there are no more q's in the string.

It is ugly because it's difficult to maintain... You basically have 3 different sub-regex inside the brackets.

Upvotes: 4

Madara's Ghost
Madara's Ghost

Reputation: 174977

Use separate expressions to make sure @ and # are present. Once they are, remove them and match for the rest of the characters/digits.

Upvotes: 0

Related Questions