Regex - multiple matches to accept - php

I am fairly new to Regex and trying to carry out 3 separate matches on a string, using .php. All 3 must match in order for it to be accepted.
I have a string that will go into a form that specifies the following:
KON-92382
Where KON (Konica) can either be: KON, HEW or CAN
Where '-' is mandatory in this position
Where 5 (strict) digit code must start with 9
So, I need to check the first 3 positions and then TRUE or FALSE
If TRUE, check 4th position and then TRUE or FALSE
Check 5th-9th position that they start with a 9 and then TRUE or FALSE
All 3 checks must result in TRUE, otherwise the check should return FALSE
End users will enter the printer tag into our internal ticketing system and these strings equate to a printer in our assets database.
So far I have tested the following as working, but I need to expand the code so that the '9' can be either 4, 5, 6, 7, 8 or 9 as I am planning to use this number to identify the class of printer (ie - 4 will be A3 Colour MFD)
/(KON|HEW|CAN)(-)(9)[0-9][0-9][0-9][0-9]/
My 'dirty' fix is as follows:
$format = "/(KON-4)|(KON-9)|(HEW-4)|(HEW-9)|(CAN-4)|(CAN-9)(-)[0-9][0-9][0-9][0-9]/";
In this example, i've only specified type 4 or 9 to keep it simple, because the question is more about matching ALL 3 criteria.
Another note, I do not want the 4-9 to be a range (reason being that I want type 5 to fail (ie. KON-51234) as I will be taking all type 5 B/W MFDs out of service pending provider removing from sites and therefore any ticket with this string should fail so that service desk know that this is not an active printer)
Any help is appreciated

You could specify different allowed numbers for every match:
^(?:KON-[46-9]|HEW-[4-9]|CAN-[4-9])\d{4}$
Explanation
^ Start of string
(?: Non capture group for the alternatives
KON-[46-9]|HEW-[4-9]|CAN-[4-9]
) Close non capture group
\d{4} Match 4 digits
$ End of string
See a regex101 demo.
Example for valid matches:
$strings = [
"KON-92382",
"KON-51234",
"HEW-71111",
"CAN-31111",
"KON-912345"
];
$pattern = "/^(?:KON-[46-9]|HEW-[4-9]|CAN-[4-9])\d{4}$/";
print_r(preg_grep($pattern, $strings));
Output
Array
(
[0] => KON-92382
[2] => HEW-71111
)

Related

Conditional regex length based on the first character

There is a string with numbers I need to validate with PHP preg_match.
If it starts with 10 or 20 or 30, I need 7 more numbers after the inital 2, but in any other cases I need 8 numbers only and don't care what are the lead characters.
The first part is the simple one
/^(1|2|3)0\d{7}$
But how can I add an ELSE part? There I need a simple
^\d{8}$
I need to match these examples:
101234567
201234567
12345678
33445566
You may use
^(?:[1-3]0\d{7}|(?![1-3]0)\d{8})$
See the regex demo
Details
^ - start of string
(?: - start of a non-capturing group:
[1-3]0\d{7} - 1, 2 or 3, then 0 and any 7 digits
| - or
(?![1-3]0)\d{8} - no 10, 20 or 30 immediately at the start of the string are allowed, then any 8 digits are matched
) - end of the group
$ - end of the string.
Here's an alternative using (?(?=regex)then|else) aka conditionals:
^(?(?=[1-3]0)[1-3]0\d{7}|\d{8})$
It literally says: if [1-3]0 is right at the start, match [1-3]0\d{7}, else match \d{8}.
Demo: https://regex101.com/r/LXoHyk/1 (examples shamelessly taken from Wiktor's answer)

Regex in conditional or with exact number of digits

I've been struggling to achieve regex with the operator or.
For example
Having the following chain:
Allowed numbers: 1, 2, 5, 6, 20
"/path/item/1"
"/path/item/2"
"/path/item/5"
etc
The regex that I have been testing is:
"/\/path\/item\/(1|2|5|6|20)/"
What I want is for regex to return true only if it is 1 or 2 or 5 or 6, etc.
But for the example of the number 20, the regex returns true for 2 and not for 20.
How can I validate each value independently, that is to say that it is only true if it is 2 and not 20. But true when it is 20 but not 2.
How would the regex be to implement this validation?
Ejemplo
You need to restrict the search such that the matched digits bring you to the end of the string:
"/\/path\/item\/(1|2|5|6|20)$/"
This will mean that the digits must exactly match, and does not involve any re-ordering of the permitted values in your regex.
Demonstrated here
The key is to add the large numbers first in the capturing or non-capturing group, such as:
^\/path\/item\/(20|1|2|5|6)$
or
^\/path\/item\/(?:20|1|2|5|6)$
or
\/path\/item\/(?:20|1|2|5|6)
Test
$re = '/^\/path\/item\/(20|1|2|5|6)$/s';
$str = '/path/item/20';
preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
var_dump($matches);
The expression is explained on the top right panel of this demo, if you wish to explore further or modify it, and in this link, you can watch how it would match against some sample inputs step by step, if you like.
Problem with your code was, whenever you sent 20 to match, 2 was matched first and was ignored as there also was 0 following. This can be resolved by giving 20 first, like this:
\/path\/item\/(20|1|2|5|6)\/
View Here: https://regex101.com/r/aJf1Q8/1

Combine two regular expressions for php

I have these two regular expression
^(((98)|(\+98)|(0098)|0)(9){1}[0-9]{9})+$
^(9){1}[0-9]{9}+$
How can I combine these phrases together?
valid phone :
just start with : 0098 , +98 , 98 , 09 and 9
sample :
00989151855454
+989151855454
989151855454
09151855454
9151855454
You haven't provided what passes and what doesn't, but I think this will work if I understand correctly...
/^\+?0{0,2}98?/
Live demo
^ Matches the start of the string
\+? Matches 0 or 1 plus symbols (the backslash is to escape)
0{0,2} Matches between 0 and 2 (0, 1, and 2) of the 0 character
9 Matches a literal 9
8? Matches 0 or 1 of the literal 8 characters
Looking at your second regex, it looks like you want to make the first part ((98)|(\+98)|(0098)|0) in your first regex optional. Just make it optional by putting ? after it and it will allow the numbers allowed by second regex. Change this,
^(((98)|(\+98)|(0098)|0)(9){1}[0-9]{9})+$
to,
^(?:98|\+98|0098|0)?9[0-9]{9}$
^ this makes the non-grouping pattern optional which contains various alternations you want to allow.
I've made few more corrections in the regex. Use of {1} is redundant as that's the default behavior of a character, with or without it. and you don't need to unnecessarily group regex unless you need the groups. And I've removed the outer most parenthesis and + after it as that is not needed.
Demo
This regex
^(?:98|\+98|0098|0)?9[0-9]{9}$
matches
00989151855454
+989151855454
989151855454
09151855454
9151855454
Demo: https://regex101.com/r/VFc4pK/1/
However note that you are requiring to have a 9 as first digit after the country code or 0.

Use regex to verify an ISBN number

I need a regex to verify ISBN number entered by user.
ISBN must be a string contains only:
[10 or 13 digits] and hyphens
I tried ^[\d*\-]{10}|[\d*\-]{13}$ but it doesn't work.
My regex only matches: 978-1-5661, 1-56619-90, 1257561035
It should returns the results below:
"978-1-56619-909-4 2" => false
"978-1-56619-909-4" => true
"1-56619-909-3 " => false
"1-56619-909-3" => true
"isbn446877428ydh" => false
"55 65465 4513574" => false
"1257561035" => true
"1248752418865" => true
I really appreciate any help.
You can use this regex with a positive lookahead:
^(?=(?:\D*\d){10}(?:(?:\D*\d){3})?$)[\d-]+$
RegEx Demo
(?=(?:\D*\d){10}(?:(?:\D*\d){3})?$) is a positive lookahead that ensures we have 10 or 13 digits in the input.
As mentioned at the accepted answer, not all 10 or 13 digit numbers are valid ISBN.
An ISBN consists of five groups of numbers that make out 13 digits. In 2007 the standard moved from 10 digits. The five groups can accept various lengths of numbers, which makes ISBN challenging to validate.
Ref. https://en.wikipedia.org/wiki/International_Standard_Book_Number
One solution is this:
^(?:ISBN(?:-13)?:?\ )?(?=[0-9]{13}$|(?=(?:[0-9]+[-\ ]){4})[-\ 0-9]{17}$)97[89][-\ ]?[0-9]{1,5}[-\ ]?[0-9]+[-\ ]?[0-9]+[-\ ]?[0-9]$
Source: O'Reilly Regular Expressions Cookbook, 2nd edition
You may find many possible regexp for ISBN validation here: https://regexlib.com/Search.aspx?k=ISBN

preg_match_all() to count the 'pattern occurs' thing

For example I have the following string 1234567890
pattern is /1|2/
preg_match_all('/1|2/', '1234567890', $out)
gives
[0] ⇒ "1"
[1] ⇒ "2"
But I need to know only the number when the whole pattern occurs (1 time in this case).
Is it possible to find it?
In other words I need to count how many times all pattern occurs
P.S.
for 'closers' and 'downvoters': the question is much wider then just regexpings
Another example:
string sdjka1gsdf1la5wlkasdfcmjsdc8fgvkj
I need to count how many times occurs set of letters a, b and c, followed by digits.
As you can see in this example there'are three occurences - a1, a5 and c8.
So how I can count them?
Example 2:
String where 1 abcd when 1 123456 where 5 when 10 abdc
I need to count how many times whe*+one digit occurs (in this case 3 times)
See preg_match_all manual:
Return Values
Returns the number of full pattern matches (which might be zero), or FALSE if an error occurred.
echo preg_match_all('/[abc]\d+/', 'sdjka1gsdf1la5wlkasdfcmjsdc8fgvkj');
3 demo at eval.in

Categories