How can I “combine” these two regular expressions in PHP?

I learn regular expression, so please calm down with me!

The username is considered valid if it does not start with _ (underscore) and contains only the word characters (letters, numbers and underscore):

 namespace Gremo\ExtraValidationBundle\Validator\Constraints; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class UsernameValidator extends ConstraintValidator { public function validate($value, Constraint $constraint) { // Violation if username starts with underscore if (preg_match('/^_', $value, $matches)) { $this->context->addViolation($constraint->message); return; } // Violation if username does not contain all word characters if (!preg_match('/^\w+$/', $value, $matches)) { $this->context->addViolation($constraint->message); } } } 

To combine them into one regex , I tried the following:

 ^_+[^\w]+$ 

To read how: add a violation if it starts with an underscore (in the end, more than one), and if at least one character is not allowed (not a letter, number or underscore). For example, does not work with "_test".

Can you help me figure out where I am going wrong?

+4
source share
4 answers

You can add a negative expression for your second regular expression:

 ^(?!_)\w+$ 

What now means, try matching the entire string, not any part of it. A line must not begin with an underscore and may contain one or more words.

See how it works

+5
source

The problem is De Morgan Law . ^_+[^\w]+$ will only match if it starts with one or more underscores, and all of the following characters are not word characters. You must match if it starts with an underscore, or any character is a character other than a word.

I think that in this case it’s easier to focus on real user names: they start with a word character other than an underscore, and all other characters are word characters. In other words, valid user names are described by the pattern ^[^\W_]\w*$ . So you can write:

 if (! preg_match('/^[^\W_]\w*$/', $value, $matches)) { 
+1
source

Of course, there are many different ways to do this. I would probably look at something along the lines of /^(?!_)[\w\d_]+/$ .

The [\w\d_]+ , combined with anchors (^ and $), essentially states that the entire string consists of only these characters. Part (?! _) Is a negative outlook. This means that the next character is not an underscore. Since it is next to the anchor ^, this ensures that the first character is not an underscore.

+1
source

A simple solution is the following:

 if (!preg_match('/^[a-zA-Z0-9]+$/', $value, $matches)) { 

you just need the \w group (including the underscore), but without the underscore, so [a-zA-Z0-9] equivalent to \w , but without the underscore.

0
source

Source: https://habr.com/ru/post/1434268/


All Articles