How to make validation username using preg_match? - php

I would like to create a preg_match function to validate my username, my code below not working perfectly, especially on Must contain at least 4 letter lowercase rules and number not more than 4 character and place behind letter
if (preg_match('/^[a-z0-9]{4,12}/', $_POST['username']))
Here are my username rules that I want to work :
Only contain letter and numbers but number is not reqired
Must contain at least 4 letter lowercase
Number not more than 4 character and place behind letter
Must be 4-12 characters
Thank you for any help you can offer.

You match these criteria, maybe this will be an option:
^[a-z](?=(?:[a-z]*\d){0,4}(?![a-z]*\d))(?=[a-z\d]{3,11}$)[a-z\d]+$
This will match
From the beginning of the string ^
Match a lowercase character [a-z]
A positive lookahead (?= which asserts that what follows is
A non capturing group (?:
Which will match a lowercase character zero or more times followed by a digit [a-z]*\d
Close non capturing group and repeat that from 0 to 4 times ){0,4}
A negative lookahead (?! Which asserts that what follows is not
A lowercase character zero or more times followed by a digit [a-z\d]*
Close negative lookahead )
Close positive lookahead )
Positive lookahead (?= which asserts that what follows is
Match a lowercase character or a digit from 3 till 11 times till the end of the string (?=[a-z\d]{3,11}$)
Close positive lookahead )
Match a lowercase character or a digit till the end of the string [a-z\d]+$
Out php example

Regex: ^[a-z]{4,8}[0-9]{0,4}$|^[a-z]{4,12}$
Details:
^ Asserts position at start of a line
$ Asserts position at the end of a line
[] Match a single character present in the list
{n,m} Matches between n and m times
| Or
PHP code:
$strings=['testtesttest', 'testtesttestr', 'test12345', 'testtest1234', 'testte123432'];
foreach($strings as $string){
$match = preg_match('~^[a-z]{4,8}[0-9]{0,4}$|^[a-z]{4,12}$~', $string);
echo ($string . ' => len: (' . strlen($string) . ') ' .($match ? 'true' : 'false')."\n");
}
Output:
testtesttest => len: (12) true
testtesttestr => len: (13) false
test12345 => len: (9) false
testtest1234 => len: (12) true
testte123432 => len: (12) false
Code demo

Related

preg_replace how to remove all numbers except alphanumeric

How to remove all numbers exept alphanumeric, for example if i have string like this:
Abs_1234abcd_636950806858590746.lands
to become it like this
Abs_1234abcd_.lands
It is probably done like this
Find (?i)(?<![a-z\d])\d+(?![a-z\d])
Replace with nothing.
Explained:
It's important to note that in the class [a-z\d] within assertions,
there exists a digit, without which could let "abc901234def" match.
(?i) # Case insensitive
(?<! [a-z\d] ) # Behind, not a letter nor digit
\d+ # Many digits
(?! [a-z\d] ) # Ahead, not a letter nor digit
Note - a speedier version exists (?i)\d(?<!\d[a-z\d])\d*(?![a-z\d])
Regex1: (?i)\d(?<!\d[a-z\d])\d*(?![a-z\d])
Completed iterations: 50 / 50 ( x 1000 )
Matches found per iteration: 2
Elapsed Time: 0.53 s, 530.56 ms, 530564 µs
Matches per sec: 188,478
Regex2: (?i)(?<![a-z\d])\d+(?![a-z\d])
Completed iterations: 50 / 50 ( x 1000 )
Matches found per iteration: 2
Elapsed Time: 0.91 s, 909.58 ms, 909577 µs
Matches per sec: 109,941
In this specific example, we can simply use _ as a left boundary and . as the right boundary, collect our digits, and replace:
Test
$re = '/(.+[_])[0-9]+(\..+)/m';
$str = 'Abs_1234abcd_636950806858590746.lands';
$subst = '$1$2';
$result = preg_replace($re, $subst, $str);
echo $result;
Demo
For your example data, you could also match not a word character or an underscore [\W_] using a character class. Then forget what is matched using \K.
Match 1+ digits that you want to replace with a empty string and assert what is on the right is again not a word character or an underscore.
[\W_]\K\d+(?=[\W_])
Regex demo

Regex to match number not preceeded by alphabets

I want to get first number from the string before the word 'minimum', preceeded by a space and not succeeded by '-'. Example:
shouldn't match the words 2-3, TT-89 etc; (ie, a number followed by - and another number or alphabets followed by - and numbers)
should match the word 2-rolls (ie, a number followed by - and alphabets)
I'm trying with the following code:
$str = "Red QQ-4555 White TT-789 Yellow Minimum order applies. This is a test";
$explodeByMinimumArray = preg_split("/minimum/i", str_replace(array( '(', ')' ), ' ', $str));
preg_match_all('/\d+(?!-\d)/', $explodeByMinimumArray[0], $numberFromStringBeforeMinimumArray);
print_r($numberFromStringBeforeMinimumArray);
This is returning $numberFromStringBeforeMinimumArray as:
Array
(
[0] => Array
(
[0] => 4555
[1] => 789
)
)
But the expected output is empty as QQ-4555 and TT-789 are preceeded by some characters.
Can anyone help me to fix this? Thanks in advance.
You need to use a negative lookbehind to ensure you do not match digits that are preceded with a letter/digit and a -:
(?<![\p{L}\d]-|\d)\d+(?!-\d)
See the regex demo.
Details
(?<![\p{L}\d]-|\d) - a negative lookbehind that fails the match if there is a letter or digit followed with - or a single digit immediately to the left of the current location
\d+ - 1+ digits
(?!-\d) - a negative lookahead that fails the match if there is a - and then a digit immediately to the right of the current location
$str = "Red QQ-4555 White TT-789 123 Yellow Minimum order applies. This is a test ";
$explodeByMinimumArray = preg_split("/minimum/i", str_replace(array( '(', ')' ), ' ', $str));
preg_match_all('/\s+\d+(?!-\d)/', $explodeByMinimumArray[0], $numberFromStringBeforeMinimumArray);
print_r($numberFromStringBeforeMinimumArray);
will give
Array
(
[0] => Array
(
[0] => 123
)
)
You may use this regex using multiple lookaround assertions:
(?<=\s)\d+\b(?!-\d+)(?=.*Minimum)
RegEx Demo
Explanation:
(?<=\s): Negative lookbehind to assert that we have a whitespace at previous position
\d+\b: Match 1+ digits followed by word boundary assertion
(?!-\d+): Negative lookahead to assert that we don't have -<digits> ahead
(?=.*Minimum): Lookahead to assert that we have Minimum text ahead

regexp - match numbers with two decimals and thousand seperator

http://www.tehplayground.com/#0qrTOzTh3
$inputs = array(
'2', // no match
'29.2', // no match
'2.48',
'8.06.16', // no match
'-2.41',
'-.54', // no match
'4.492', // no match
'4.194,32',
'39,299.39',
'329.382,39',
'-188.392,49',
'293.392,193', // no match
'-.492.183,33', // no match
'3.492.249,11',
'29.439.834,13',
'-392.492.492,43'
);
$number_pattern = '-?(?:[0-9]|[0-9]{2}|[0-9]{3}[\.,]?)?(?:[0-9]|[0-9]{2}|[0-9]{3})[\.,][0-9]{2}(?!\d)';
foreach($inputs as $input){
preg_match_all('/'.$number_pattern.'/m', $input, $matches);
print_r($matches);
}
It seems you are looking for
$number_pattern = '-?(?<![\d.,])\d{1,3}(?:[,.]\d{3})*[.,]\d{2}(?![\d.])';
See the PHP demo and a regex demo.
The anchors are not used, there are lookarounds on both sides of the pattern instead.
Pattern details:
-? - an optional hyphen
(?<![\d.,]) - there cannot be a digit, comma or dot befire the current location
-\d{1,3} - 1 to 3 digits
(?:[,.]\d{3})* - zero or more sequences of a comma or dot followed with 3 digits
[.,] - a comma or dot
\d{2} - 2 digits that are
(?![\d.]) - not followed with a digit or dot.
Note in PHP, you do not need to specify the /m MULTILINE mode and use the $ end of string anchor,
preg_match_all('/'.$number_pattern.'/', $input, $matches);
is enough to match the numbers you need in larger texts.
If you need to match them as standalone strings, use a simpler
^-?\d{1,3}(?:[,.]\d{3})*[.,]\d{2}$
See the regex demo.

split string in numbers and text but accept text with a single digit inside

Let's say I want to split this string in two variables:
$string = "levis 501";
I will use
preg_match('/\d+/', $string, $num);
preg_match('/\D+/', $string, $text);
but then let's say I want to split this one in two
$string = "levis 5° 501";
as $text = "levis 5°"; and $num = "501";
So my guess is I should add a rule to the preg_match('/\d+/', $string, $num); that looks for numbers only at the END of the string and I want it to be between 2 and 3 digits.
But also the $text match now has one number inside...
How would you do it?
To slit a string in two parts, use any of the following:
preg_match('~^(.*?)\s*(\d+)\D*$~s', $s, $matches);
This regex matches:
^ - the start of the string
(.*?) - Group 1 capturing any one or more characters, as few as possible (as *? is a "lazy" quantifier) up to...
\s* - zero or more whitespace symbols
(\d+) - Group 2 capturing 1 or more digits
\D* - zero or more characters other than digit (it is the opposite shorthand character class to \d)
$ - end of string.
The ~s modifier is a DOTALL one forcing the . to match any character, even a newline, that it does not match without this modifier.
Or
preg_split('~\s*(?=\s*\d+\D*$)~', $s);
This \s*(?=\s*\d+\D*$) pattern:
\s* - zero or more whitespaces, but only if followed by...
(?=\s*\d+\D*$) - zero or more whitespaces followed with 1+ digits followed with 0+ characters other than digits followed with end of string.
The (?=...) construct is a positive lookahead that does not consume characters and just checks if the pattern inside matches and if yes, returns "true", and if not, no match occurs.
See IDEONE demo:
$s = "levis 5° 501";
preg_match('~^(.*?)\s*(\d+)\D*$~s', $s, $matches);
print_r($matches[1] . ": ". $matches[2]. PHP_EOL);
print_r(preg_split('~\s*(?=\s*\d+\D*$)~', $s, 2));

What would be Regex to match the following 10-digit numbers?

What would be Regex to match the following 10-digit numbers:
0108889999 //can contain nothing except 10 digits
011 8889999 //can contain a whitespace at that place
012 888 9999 //can contain two whitespaces like that
013-8889999 // can contain one dash
014-888-9999 // can contain two dashes
If you're just looking for the regex itself, try this:
^(\d{3}(\s|\-)?){2}\d{4}$
Put slightly more legibly:
^ # start at the beginning of the line (or input)
(
\d{3} # find three digits
(
\s # followed by a space
| # OR
\- # a hyphen
)? # neither of which might actually be there
){2} # do this twice,
\d{4} # then find four more digits
$ # finish at the end of the line (or input)
EDIT: Oops! The above was correct, but it was also too lenient. It would match things like 01088899996 (one too many characters) because it liked the first (or the last) 10 of them. Now it's more strict (I added the ^ and $).
I'm assuming you want a single regex to match any of these examples:
if (preg_match('/(\d{3})[ \-]?(\d{3})[ \-]?(\d{4})/', $value, $matches)) {
$number = $matches[1] . $matches[2] . $matches[3];
}
preg_match('/\d{3}[\s-]?\d{3}[\s-]?\d{4}/', $string);
0108889999 // true
011 8889999 // true
012 888 9999 // true
013-8889999 // true
014-888-9999 // true
To match the specific parts:
preg_match('/(\d{3})[\s-]?(\d{3})[\s-]?(\d{4}/)', $string, $matches);
echo $matches[1]; // first 3 numbers
echo $matches[2]; // next 3 numbers
echo $matches[3]; // next 4 numbers
You can try this pattern. It satisfies your requirements.
[0-9]{3}[-\s]?[0-9]{3}[-\s]?[0-9]{4}
Also, you can add more conditions to the last character by appending [\s.,]+: (phone# ending with space, dot or comma)
[0-9]{3}[-\s]?[0-9]{3}[-\s]?[0-9]{4}[\s.,]+

Categories