views:

153

answers:

2

Hi,

I have a pattern with a small list of words that are illegal to use as nicknames set in a pattern variable like this:

$pattern = webmaster|admin|webadmin|sysadmin

Using preg_match, how can I achieve so that nicknames with these words are forbidden, but registering something like "admin2" or "thesysadmin" is allowed?

This is the expression I have so far:

preg_match('/^['.$pattern.']/i','admin');

// Should not be allowed

Note: Using a \b didn't help much.

A: 

So, the forbidden words can be part of their username but not the whole thing?

In .NET, the pattern would be:

 Allowed = Not RegEx.Match("admin", "^(webmaster|admin|webadmin|sysadmin)$")

The "^" matches the beginning of the string, the "$" matches the end, so it's looking for an exact match on one of those words. I'm a bit fuzzy on the corresponding PHP syntax.

richardtallent
+2  A: 

Hi,

What about not using regex at all ?
And working with explode and in_array ?

For instance, this would do :

$pattern = 'webmaster|admin|webadmin|sysadmin';
$forbidden_words = explode('|', $pattern);

It explodes your pattern into an array, using | as separator.


And this :

$word = 'admin';
if (in_array($word, $forbidden_words)) {
    echo "<p>$word is not OK</p>";
} else {
    echo "<p>$word is OK</p>";
}

will get you

admin is not OK

Whereas this (same code ; only the word changes) :

$word = 'admin2';
if (in_array($word, $forbidden_words)) {
    echo "<p>$word is not OK</p>";
} else {
    echo "<p>$word is OK</p>";
}

will get you

admin2 is OK

This way, no need to worry about finding the right regex, to match full-words : it'll just match exact words ;-)


Edit : one problem might be that the comparison will be case-sensitive :-(
Working with everything in lowercase will help with that :

$pattern = strtolower('webmaster|admin|webadmin|sysadmin');  // just to be sure ;-)
$forbidden_words = explode('|', $pattern);

$word = 'aDMin';
if (in_array(strtolower($word), $forbidden_words)) {
    echo "<p>$word is not OK</p>";
} else {
    echo "<p>$word is OK</p>";
}

Will get you :

aDMin is not OK

(I saw the 'i' flag in the regex only after posting my answer ; so, had to edit it)


Edit 2 : and, if you really want to do it with a regex, you need to know that :

  • ^ marks the beginning of the string
  • and $ marks the end of the string

So, something like this should do :

$pattern = 'webmaster|admin|webadmin|sysadmin';

$word = 'admin';
if (preg_match('#^(' . $pattern . ')$#i', $word)) {
    echo "<p>$word is not OK</p>";
} else {
    echo "<p>$word is OK</p>";
}

$word = 'admin2';
if (preg_match('#^(' . $pattern . ')$#i', $word)) {
    echo "<p>$word is not OK</p>";
} else {
    echo "<p>$word is OK</p>";
}

Parentheses are probably not necessary, but I like using them, to isolate what I wanted.

And, you'll get the same kind of output :

admin is not OK

admin2 is OK

You probably don't want to use [ and ] : they mean "any character that is between us", and not "the whole string that is between us".

And, as the reference : manual of the preg syntax ;-)

Pascal MARTIN
Great potatoes! That's one informative reply, I'll check out the reg-exp you stated. The in array is of course a very valid suggestion to consider. Thanks again Martin!
bakkelun
You're welcome :-) And have fun !
Pascal MARTIN
As a sidenote: It's useful to use the strtolower on the nick as well, to control the control.
bakkelun
The parentheses *are* required. Without them, the anchors (`^` and `$`) would "stick" to the first and last word in the list, respectively. Alternation (`'|'`) has the lowest precedence of all regex operators.
Alan Moore