Can you help simplify my ip range matching regex? - php

I have a regex that will match IP addresses.
it looks like:
^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|*|25[0-5]-25[0-5]|2[0-4][0-9]-25[0-5]|2[0-4][0-9]-2[0-4][0-9]|[01]?[0-9][0-9]?-25[0-5]|[01]?[0-9][0-9]?-2[0-4][0-9]|[01]?[0-9][0-9]?-[01]?[0-9][0-9])$
which you will mostly recognise from many other posts here on SO. however I have modded it to match the range form XXX.XXX.XXX.XXX-XXY
However it now seems a little complex, particularly the final () capture. I would like some help to simplify this regex if possible.
Just to be clear
aaaa - not matched
999.1.1.1 - not matched
1.1.1.999 - not matched
192.168.2.1 - matched
192.168.2.* - matched
192.168.2.10-20 - matched
EDIT
I forgot to mention that I need the existing capture groups as well.

You could perhaps use optional groups (?: ... )? instead and use another grouping for the first 3 parts of the IP?
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
(?:25[0-5](?:-25[0-5])?|
2[0-4][0-9](?:-(?:25[0-5]|2[0-4][0-9]))?|
[01]?[0-9][0-9]?(?:-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))?|
\*)$
regex101 demo
Updated with capture groups
^((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\.
((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\.
((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\.
(25[0-5](?:-25[0-5])?|
2[0-4][0-9](?:-(?:25[0-5]|2[0-4][0-9]))?|
[01]?[0-9][0-9]?(?:-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))?|
\*)$

This works -
^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\-(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(\*))$
As can be seen here

This should work and is a bit shorter:
^((25[0-5]|2[0-4]\d|[01]?\d{1,2})\.){3}(\*|(25[0-5]|2[0-4]\d|[01]?\d{1,2}))(\-(25[0-5]|2[0-4]\d|[01]?\d{1,2}))?$
See:
http://regex101.com/r/sD9iZ0

Related

RegEx to extract city and state from string AND know when someone leaves out the state part

i have the following code:
preg_match("/^(.+)[,\\s]+(.+?)\s*(\d{5})?$/", trim($searchbox), $matches);
list($arr['add'], $arr['city'], $arr['state']) = $matches;
$citystr = trim(str_replace(',', '', $arr['city']));
$statestr = trim($arr['state']);
This works great when someone types in "Granite Bay, CA", however i would like to modify it to catch when someone leave out the ", CA" part. So if someone only types "granite Bay", the code above is taking "Bay" as the state - thats no good. It also fails if someone adds a zip to the end like "Granite Bay, CA 00000"
Are there any modifications to this RegEx that i can do to avoid both these senarios?
TIA
Yes, you can build a less permissive/more detailed pattern:
^\h*([^,\s]+(?:\h+[^,\s]+)*+)\h*(?:,\h*([A-Z]+))?\h*(\d{5})?\h*$
demo
([^,\s]+(?:\h+[^,\s]+)*+) catches the city name as: something that doesn't start nor end with whitespaces and eventually in several parts.
(?:,\h*([A-Z]+))? makes all the state part optional. Note that I have chosen only uppercase letters for the state, but you can also make it case insensitive, it doesn't matter since the important point is the comma.
As an aside, if you want to be sure of what enter a user, use one field per information (one for the city, one for the state, one for the zip code).
You could go for:
^ # start of the string
(?P<town>[A-Z][^,]+) # uppercase, followed by not a comma
(?> # a non-capturing group
,\h*\K # a comma, horizontal whitespace, \K
(?P<state>[A-Z]{2}) # two UPPERCASE letters
)? # make the whole group optional
See a demo on regex101.com.
To be sure, you'll likely need some database of towns and states to check against, though (the above expression allows XY for a state as well), or as #Casimir points out, use several fields for each information.

PHP Regex Not Quite Working

I am using the following regex:
^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$
I use this regex to check for valid prices -- so it catches/rejects things like xxx, or llddd or 34.23dsds
and allows things like 100 or 120.00
The problem with it seems to be if it is blank(empty) it passes as valid which it should not -- any ideas how to change this??
Thanks
One of your problems is that you use the dot in your regex which stands for "any character". If you mean a dot you need to escape it like this \.
Also you should have at least one number in it so exchange the asterisk * by a + for "one or more".
Then you can have .,.,.,.,.,.,- if you do not remove the comma and dot from the first part:
^[0-9]+(([\.,][-])|([\.,][0-9]{2}))?$
Taking yoiur regex and just solving the "don't match blanks" problem:
^[0-9.,]+(([.,][-])|([.,][0-9]{2}))?$
the * allows 0 or more, while the + allows 1 or more, thus the * allowed blanks but the + will not, instead there must be at least one digit.
EDIT:
You should clean this regex up a bit to be
^[0-9]+(?:[.,-](?:[0-9]{2})?)?$
This solves the matching of ",,,"
http://www.regextester.com/?fam=95185
EDIT 2: #Fuzzzzel pointed out that this did not match the case "50,-" which we assume you would like to match and that removing capturing groups is presumptive. Here's the latest iteration of my suggested regex:
^[0-9]+([.,-](-|([0-9]{2}))?)?$

php regex to get the gif id from giphy

i want one php regex to extract the id (VmzI60RQG0fuw) from these
http://i.giphy.com/VmzI60RQG0fuw.gif
https://media.giphy.com/media/VmzI60RQG0fuw/giphy.gif
http://giphy.com/gifs/VmzI60RQG0fuw
http://giphy.com/gifs/music-videos-mariah-carey-dreamlover-VmzI60RQG0fuw
i tested this, but its not work on the 3 probability
preg_match('~(media\.giphy\.com/media/([^ /]+)/giphy\.gif|i.giphy.com/([^ /]+).gif)~i', $this->url, $matches)
Here is one that should work:
'~https?://(?|media\.giphy\.com/media/([^ /]+)/giphy\.gif|i\.giphy\.com/([^ /]+)\.gif|giphy\.com/gifs/(?:.*-)?([^ /]+))~i'
See the regex demo
The third alternative is giphy\.com/gifs/(?:.*-)?([^ /]+):
giphy\.com/gifs/ - a subpath giphy.com/gifs/
(?:.*-)? - (optional group, the text may go missing due to (?:...)? construct) matches all characters up to the last - (perhaps, replacing with \S*- or [^\s/]*- can make it a bit more precise)
([^ /]+) - matches and captures the ID (one or more characters other than a space and /).
Since it is for PHP, you can also use a branch reset ((?|...|...)) so that all the captured groups could have one and the same ID #1.

Get 'XXX' value using a RegEx in PHP

I need some help building a regex for get the value of XXX in the following set of possible matches:
+58XXXYYYYYYY
+580XXXYYYYYYY
0XXXYYYYYYY
XXXYYYYYYY
This are phone numbers so XXX is dynamic and will not hold always the same value. The RegEx is intended to be used on PHP so I know I should use preg_match() function but I have not idea about the regex. Can any give me some advice on this?
This sounds like it matches your requirements:
(\d{3})\d{7}$
With a Live Demo
If you want to match the last 3 numbers, you could use /([0-9]{3,3})$/.
The parenthesis indicates a capturing group (what you are looking for). Inside that group you want to match a pattern [...]of any number 0-9 exactly 3 times {3,3}. And finally you want to match the last occurrence of this pattern, so the $ indicates the end of the line.
A very handy tool to building simple regex queries is Debuggex. I use it all the time!

Retrieve 0 or more matches from comma separated list inside parenthesis using regex

I am trying to retrieve matches from a comma separated list that is located inside parenthesis using regular expression. (I also retrieve the version number in the first capture group, though that's not important to this question)
What's worth noting is that the expression should ideally handle all possible cases, where the list could be empty or could have more than 3 entries = 0 or more matches in the second capture group.
The expression I have right now looks like this:
SomeText\/(.*)\s\(((,\s)?([\w\s\.]+))*\)
The string I am testing this on looks like this:
SomeText/1.0.4 (debug, OS X 10.11.2, Macbook Pro Retina)
Result of this is:
1. [6-11] `1.0.4`
2. [32-52] `, Macbook Pro Retina`
3. [32-34] `, `
4. [34-52] `Macbook Pro Retina`
The desired result would look like this:
1. [6-11] `1.0.4`
2. [32-52] `debug`
3. [32-34] `OS X 10.11.2`
4. [34-52] `Macbook Pro Retina`
According to the image above (as far as I can see), the expression should work on the test string. What is the cause of the weird results and how could I improve the expression?
I know there are other ways of solving this problem, but I would like to use a single regular expression if possible. Please don't suggest other options.
When dealing with a varying number of groups, regex ain't the best. Solve it in two steps.
First, break down the statement using a simple regex:
SomeText\/([\d.]*) \(([^)]*)\)
1. [9-14] `1.0.4`
2. [16-55] `debug, OS X 10.11.2, Macbook Pro Retina`
Then just explode the second result by ',' to get your groups.
Probably the \G anchor works best here for binding the match to an entry point. This regex is designed for input that is always similar to the sample that is provided in your question.
(?<=SomeText\/|\G(?!^))[(,]? *\K[^,)(]+
(?<=SomeText\/|\G) the lookbehind is the part where matches should be glued to
\G matches where the previous match ended (?!^) but don't match start
[(,]? *\ matches optional opening parenthesis or comma followed by any amount of space
\K resets beginning of the reported match
[^,)(]+ matches the wanted characters, that are none of ( ) ,
Demo at regex101 (grab matches of $0)
Another idea with use of capture groups.
SomeText\/([^(]*)\(|\G(?!^),? *([^,)]+)
This one without lookbehind is a bit more accurate (it also requires the opening parenthesis), of better performance (needs fewer steps) and probably easier to understand and maintain.
SomeText\/([^(]*)\( the entry anchor and version is captured here to $1
|\G(?!^),? *([^,)]+) or glued to previous match: capture to $2 one or more characters, that are not , ) preceded by optional space or comma.
Another demo at regex101
Actually, stribizhev was close:
(?:SomeText\/([^() ]*)\s*\(|(?!^)\G),?\s*([^(),]+)(?=[^()]*\))
Just had to make that one class expect at least one match
(?:SomeText\/([0-9.]+)\s*\(|(?!^)\G),?\s*([^(),]+)(?=[^()]*\)) is a little more clear as long as the version number is always numbers and periods.
I wanted to come up with something more elegant than this (though this does actually work):
SomeText\/(.*)\s\(([^\,]+)?\,?\s?([^\,]+)?\,?\s?([^\,]+)?\,?\s?([^\,]+)?\,?\s?([^\,]+)?\,?\s?([^\,]+)?\,?\s?\)
Obviously, the
([^\,]+)?\,?\s?
is repeated 6 times.
(It can be repeated any number of times and it will work for any number of comma-separated items equal to or below that number of times).
I tried to shorten the long, repetitive list of ([^\,]+)?\,?\s? above to
(?:([^\,]+)\,?\s?)*
but it doesn't work and my knowledge of regex is not currently good enough to say why not.
This should solve your problem. Use the code you already have and add something like this. It will determine where commas are in your string and delete them.
Use trim() to delete white spaces at the start or the end.
$a = strpos($line, ",");
$line = trim(substr($line, 55-$a));
I hope, this helps you!

Categories