Regex to match number not preceeded by alphabets - php

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

Related

Extract Key from URL with Preg_Match in PHP

I haves this URL
https://test.com/file/5gdxyYpb#_FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE
I need to create with preg_mach this condition:
$match[0]=5gdxyYpb#_FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE
$match[1]=5gdxyYpb
$match[2]=_FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE
I try difference pattern the mos closed was this one. e\/(.*?)\#(.*).
Please any recommendation. (If necessary in Preg_Match).
Thank you,
You might use 2 capturing groups and make use of \K to not match the first part of the url to get the desired matches.
https?://.*/\K([^#\s]+)#(\S+)
https?:// Match the protocol with optional s, then ://
.*/ Match until the last occurrence of /
\K Forget what is matched until here
([^#\s]+) Capture group 1, match 1+ occurrences of any char except a # or whitespace char
# Match the #
(\S+) Capture group 2, match 1+ occurrences of a non whitespace char
Regex demo | Php demo
$url = "https://test.com/file/5gdxyYpb#_FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE";
$pattern = "~https?://.*/\K([^#]+)#(.*)~";
$res = preg_match($pattern, $url, $matches);
print_r($matches);
Output
Array
(
[0] => 5gdxyYpb#_FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE
[1] => 5gdxyYpb
[2] => _FWRc4T12baPrppZIwVQ5i18Sq16f7TXU82LJwY_BjE
)

regex expected value in a postion depends on a random value in another position

I need regex to find all shortcode tag pairs that look like this [sc1-g-data]b[/sc1-g-data] but the number next to the sc can vary but they must match.
So something like this won't work \[sc(.*?)\-((.|\n)*?)\[\/sc(.*?)\- as this matches unmatching tag pairs like this which i don't want [sc1-g-data]b[/sc2-g-data]
so the expected number in the second tag depends on a random number in the first tag
You may use a regex like:
\[(sc\d*-[^\]\[]*)\]([\s\S]*?)\[\/\1\]
See the regex demo
\[ - a [ char
(sc\d*-[^\]\[]*) - Capturing group 1: sc, 0+ digits, -, and then 0+ chars other than ] and [
\] - a ] char
([\s\S]*?) - Capturing group 2: any 0+ chars, as few as possible
\[\/ - a [/ string
\1 - the same text stored in Group 1
\] - a ] char
See the regex graph:
PHP demo:
$pattern = '~\[(sc\d*-[^][]*)](.*?)\[/\1]~s';
$string = '[sc1-g-data]a[/sc1-g-data] ';
if (preg_match($pattern, $string, $matches)) {
print_r($matches);
}
Mind the use of a single quoted string literal, if you use a double quoted one you will need to use \\1, not \1 as '\1' != "\1" in PHP.
Output:
Array
(
[0] => [sc1-g-data]a[/sc1-g-data]
[1] => sc1-g-data
[2] => a
)
If your tags are just anything between brackets [blah][/blah] you can use:
\[(.*?)\].*?\[\/\1\]

Regex of number inside brackets

I need to get the float number inside brackets..
I tried this '([0-9]*[.])?[0-9]+' but it returns the first number like 6 in the first example.
Also I tried this
'/\((\d+)\)/'
but it returns 0.
Please note that I need the extracted number either int or float.
Can u plz help
As you need to match bracket also, You need to add () in regular expression:
$str = 'Serving size 6 pieces (40)';
$str1 = 'Per bar (41.5)';
preg_match('#\(([0-9]*[.]?[0-9]+)\)#', $str, $matches);
print_r($matches);
preg_match('#\(([0-9]*[.]?[0-9]+)\)#', $str1, $matches);
print_r($matches);
Output:
Array
(
[0] => (40)
[1] => 40
)
Array
(
[0] => (41.5)
[1] => 41.5
)
DEMO
You could escape brackets:
$str = 'Serving size 6 pieces (41.5)';
if (preg_match('~\((\d+.?\d*)\)~', $str, $matches)) {
print_r($matches);
}
Outputs:
Array
(
[0] => (41.5)
[1] => 41.5
)
Regex:
\( # open bracket
( # capture group
\d+ # one or more numbers
.? # optional dot
\d* # optional numbers
) # end capture group
\) # close bracket
You could also use this to get only one digit after the dot:
'~\((\d+.?\d?)\)~'
You need to escape the brackets
preg_match('/\((\d+(?:\.\d+)?)\)/', $search, $matches);
explanation
\( escaped bracket to look for
( open subpattern
\d a number
+ one or more occurance of the character mentioned
( open Group
?: dont save data in a subpattern
\. escaped Point
\d a number
+ one or more occurance of the character mentioned
) close Group
? one or no occurance of the Group mentioned
) close subpattern
\) escaped closingbracket to look for
matches numbers like
1,
1.1,
11,
11.11,
111,
111.111 but NOT .1, .
https://regex101.com/r/ei7bIM/1
You could match an opening parenthesis, use \K to reset the starting point of the reported match and then match your value:
\(\K\d+(?:\.\d+)?(?=\))
That would match:
\( Match (
\K Reset the starting point of the reported match
\d+ Match one or more digits
(?: Non capturing group
\.\d+ Match a dot and one or more digits
)? Close non capturing group and make it optional
(?= Positive lookahead that asserts what follows is
\) Match )
) Close posive lookahead
Demo php

regex inside tags with specified string

I'm not very good at regex but i have a string like this :
$str = '<span id="MainStatuSSpan" style="background: brown;"> Incoming: 012345678 Group- SUPERMONEY Fronter: - 992236 UID: Y3281602190002004448</span>';
$pattern = '/(?:Fronter: - )[0-9]{1,6}/i';
preg_match($pattern, $str, $matches);
print_r($matches);
/*** ^^^^^^^ This prints :*/
Array ( [0] => Fronter: - 992236 )
In case of the Fronter is not with - or spaces I don't get the Fronter - number.
Can anyone help with an example that works in any case, there is always a Fronter and a number.
you can use Fronter:\W*[0-9]{1,6}
Fronter:\W*[0-9]{1,6} : match Fronter:
\W* : zero or more non-word characters
[0-9]{1,6} one to six digits
you regex will also find a match with Fronter:99222236 so you must use \b to avoid overflow digit length
Fronter:[- ]*[0-9]{1,6}\b

Split string on non-alphanumeric characters and on positions between digits and non-digits

I'm trying to split a string by non-alphanumeric delimiting characters AND between alternations of digits and non-digits. The end result should be a flat array of consisting of alphabetic strings and numeric strings.
I'm working in PHP, and would like to use REGEX.
Examples:
ES-3810/24MX should become ['ES', '3810', '24', 'MX']
CISCO1538M should become ['CISCO' , '1538', 'M']
The input file sequence can be indifferently DIGITS or ALPHA.
The separators can be non-ALPHA and non-DIGIT chars, as well as a change between a DIGIT sequence to an APLHA sequence, and vice versa.
The command to match all occurrances of a regex is preg_match_all() which outputs a multidimensional array of results. The regex is very simple... any digit ([0-9]) one or more times (+) or (|) any letter ([A-z]) one or more times (+). Note the capital A and lowercase z to include all upper and lowercase letters.
The textarea and php tags are inluded for convenience, so you can drop into your php file and see the results.
<textarea style="width:400px; height:400px;">
<?php
foreach( array(
"ES-3810/24MX",
"CISCO1538M",
"123ABC-ThatsHowEasy"
) as $string ){
// get all matches into an array
preg_match_all("/[0-9]+|[[:upper:][:lower:]]+/",$string,$matches);
// it is the 0th match that you are interested in...
print_r( $matches[0] );
}
?>
</textarea>
Which outputs in the textarea:
Array
(
[0] => ES
[1] => 3810
[2] => 24
[3] => MX
)
Array
(
[0] => CISCO
[1] => 1538
[2] => M
)
Array
(
[0] => 123
[1] => ABC
[2] => ThatsHowEasy
)
$str = "ES-3810/24MX35 123 TEST 34/TEST";
$str = preg_replace(array("#[^A-Z0-9]+#i","#\s+#","#([A-Z])([0-9])#i","#([0-9])([A-Z])#i"),array(" "," ","$1 $2","$1 $2"),$str);
echo $str;
$data = explode(" ",$str);
print_r($data);
I could not think on a more 'cleaner' way.
The most direct preg_ function to produce the desired flat output array is preg_split().
Because it doesn't matter what combination of alphanumeric characters are on either side of a sequence of non-alphanumeric characters, you can greedily split on non-alphanumeric substrings without "looking around".
After that preliminary obstacle is dealt with, then split on the zero-length positions between a digit and a non-digit OR between a non-digit and a digit.
/ #starting delimiter
[^a-z\d]+ #match one or more non-alphanumeric characters
| #OR
\d\K(?=\D) #match a number, then forget it, then lookahead for a non-number
| #OR
\D\K(?=\d) #match a non-number, then forget it, then lookahead for a number
/ #ending delimiter
i #case-insensitive flag
Code: (Demo)
var_export(
preg_split('/[^a-z\d]+|\d\K(?=\D)|\D\K(?=\d)/i', $string, 0, PREG_SPLIT_NO_EMPTY)
);
preg_match_all() isn't a silly technique, but it doesn't return the array, it returns the number of matches and generates a reference variable containing a two dimensional array of which the first element needs to be accessed. Admittedly, the pattern is shorter and easier to follow. (Demo)
var_export(
preg_match_all('/[a-z]+|\d+/i', $string, $m) ? $m[0] : []
);

Categories