Regex get matches for ranges in IPv4 addresses with octet notation - regex

I want to use a Regex expression to get all ranges in an IP Address provided.
Examples:
192.168.0-255.1 would return 0-255
192.168.0-255.1-10 would return 0-255 and 1-10
192.168.0-10,42,80-200.1-10,128-255 would return 0-10, 80-200, 1-10, 128-255.
BONUS: I'd also like to be able to separate these expressions into 4 different ones to determine which octet the IP range is in.
Example: 192.168-180.0.1 I'd like to get 168-180 here from an expression that looks for a match with only one period left of the substring and two periods somewhere in the right side of the substring.

Something like this?
<?php
$input = <<<INPUT
192.168.0-255.1
192.168.0-255.1-10
192.168.0-10,42,80-200.1-10,128-255
INPUT;
preg_match_all("/[0-9]+\-[0-9]+/m", $input, $m);
print_r($m);
Output:
Array
(
[0] => Array
(
[0] => 0-255
[1] => 0-255
[2] => 1-10
[3] => 0-10
[4] => 80-200
[5] => 1-10
[6] => 128-255
)
)
[0-9]+ 1 or more number
- "-" escaped
[0-9]+ 1 or more number

Related

Preg_match / split barcode

I am struggeling with reading a GS1-128 barcode, and trying to split it up into the segments it contains, so I can fill out a form automatically.
But I can't figure it out. Scanning my barcode gives me the following:
]d2010704626096200210KT0BT2204[GS]1726090021RNM5F8CTMMBHZSY7
So I tried starting with preg_match and made the following:
/]d2[01]{2}\d{14}[10|17|21]{2}(\w+)/
Which gives me this result:
Array ( [0] => ]d2010704626096200210KT0BT2204 [1] => KT0BT2204 )
Now [1] is actually correct, men [0] isnt, so I have run into a wall.
In the end, this is the result I would like (without 01,10,17,21):
(01) 07046260962002
(10) KT0BT2204
(17) 60900
(21) RNM5F8CTMMBHZSY7
01 - Always 14 chars after
17 - Always 6 chars after
10 can be up to 20 chars, but always has end delimiter <GS> - But if barcode ends with 10 <GS> is not present
21 can be up to 20 chars, but always has end delimiter <GS> - But if barcode ends with 21 <GS> is not present
I tried follwing this question: GS1-128 and RegEx
But I couldnt figure it out.
Anyone that can help me?
This regex should do what you want (note I've split it into separate lines for clarity, you can use it like this with the x (extended) flag, or convert it back to one line):
^]d2(?:
01(?P<g01>.{14})|
10(?P<g10>(?:(?!\[GS]).){1,20})(?:\[GS]|$)|
17(?P<g17>.{6})|
21(?P<g21>(?:(?!\[GS]).){1,20})(?:\[GS]|$)
)+$
It looks for
start-of-line ^ followed by a literal ]d2 then one or more of
01 followed by 14 characters (captured in group g01)
10 followed by up to 20 characters, terminated by either [GS] or end-of-line (captured in group g10)
17 followed by 6 characters (captured in group g17)
21 followed by up to 20 characters, terminated by either [GS] or end-of-line (captured in group g21)
finishing with end-of-line $
Note that we need to use tempered greedy tokens to avoid the situation where a 10 or 21 code might swallow a following code (as in the second example in the regex demo below).
Demo on regex101
In PHP:
$barcode = ']d201070462608682672140097289158930[GS]10101656[GS]17261130';
preg_match_all('/^]d2(?:
01(?P<g01>.{14})|
10(?P<g10>(?:(?!\[GS]).){1,20})(?:\[GS]|$)|
17(?P<g17>.{6})|
21(?P<g21>(?:(?!\[GS]).){1,20})(?:\[GS]|$)
)+$/x', $barcode, $matches);
print_r($matches);
Output:
Array
(
[0] => Array
(
[0] => ]d201070462608682672140097289158930[GS]10101656[GS]17261130
)
[g01] => Array
(
[0] => 07046260868267
)
[1] => Array
(
[0] => 07046260868267
)
[g10] => Array
(
[0] => 101656
)
[2] => Array
(
[0] => 101656
)
[g17] => Array
(
[0] => 261130
)
[3] => Array
(
[0] => 261130
)
[g21] => Array
(
[0] => 40097289158930
)
[4] => Array
(
[0] => 40097289158930
)
)
Demo on 3v4l.org
]d2[01]{2}(\d{14})(?:10|17|21)(\w+)\[GS\](\w+)(?:10|17|21)(\w+)
You can try something like this.
See demo..
https://regex101.com/r/Bw238X/1

How to use regex in PostgreSQL to put one point every 2 char?

How can I replace a string by putting a dot every two characters using the regexp_replace function?
For example:
1 => 1
12 => 12
123 => 12.3
1234 => 12.34
12345 => 12.34.5
123456 => 12.34.56
... and so on.
I tried some odds but I did not succeed.
Match (.{2})(?!$) globally and replace it with $1..
The (?!$) part is a negative look ahead preventing a match on the last two numbers. It avoids 12.34 from being 12.34..
test=> select regexp_replace('12345678', '(.{2})(?!$)', '\1.', 'g');
regexp_replace
----------------
12.34.56.78
Demo

Regexp to capture overlapping matches

I am looking for a regexp option or trick to capture all possible strings in a regexp when matches can overlap.
Example : /A.A/ in string "ABACADA"
It finds : ABA, ADA and not ACA !!
I would like : ABA, ACA, ADA
I am working in PHP, but it can be applied to other languages
preg_match_all('/A.A/',"ABACADA",$matches);
var_dump($matches[0]);
// output : array (size=2)
// 0 => string 'ABA' (length=3)
// 1 => string 'ADA' (length=3)
Can you help me? Thanks
You can use a positive lookahead assertion to get all 3 matches:
(?=(A.A))
RegEx Demo
For your input it finds 3 matches in captured group #1:
ABA
ACA
ADA
PHP Code:
if (preg_match_all('/(?=(A.A))/', "ABACADA", $m))
print_r($m[1]); // printing index 1
Output:
Array
(
[0] => ABA
[1] => ACA
[2] => ADA
)

RegEx With A Street Prefix And Wildcards

I can't figure out the correct regex expression for what I am looking for. Essentially what I need is the following.
If user searches for a street prefix such as N W E S and includes a wildcard (%,*) that the regex ignores it. I only want the regex to work with N W E S exclusively.
So how do I write the regex to say, if you have a character next to you then ignore. This is what I have so far.
^(N|S|W|E)\b
But it's picking up N% and other wildcards... I don't want it too.
Description
This regex will match only streets with N, S, E, W followed by whitespace and more text or the end of the line.
^([nsew])\b(?:\s.*?)?$
Group 0 will receive the entire matched value
Group 1 will receive just the N, S, E, or W
N Wisconsin Drive
S Voter Booth
E Kitten Ave
W Washington Street
Noghtington Lane
Silver Stone Drive
Edans Expressway
Wireware Waythrough
Example
You didn't specify a language, so I picked PHP to demo the regex.
<?php
$sourcestring="N Wisconsin Drive
S Voter Booth
E Kitten Ave
W Washington Street
Noghtington Lane
Silver Stone Drive
Edans Expressway
Wireware Waythrough";
Dim re As Regex = New Regex("^([nsew])\b(?:\s.*?)?$",RegexOptions.IgnoreCase OR RegexOptions.Multiline)
Dim mc as MatchCollection = re.Matches(sourcestring)
Dim mIdx as Integer = 0
For each m as Match in mc
For groupIdx As Integer = 0 To m.Groups.Count - 1
Console.WriteLine("[{0}][{1}] = {2}", mIdx, re.GetGroupNames(groupIdx), m.Groups(groupIdx).Value)
Next
mIdx=mIdx+1
Next
End Sub
End Module
$matches Array:
(
[0] => Array
(
[0] => N Wisconsin Drive
[1] => S Voter Booth
[2] => E Kitten Ave
[3] => W Washington Street
)
[1] => Array
(
[0] => N
[1] => S
[2] => E
[3] => W
)
)
^ in that case is the beginning of the string rather than "not." You can do this with a negative lookahead.
[NSWE](?!%|\*)
From your question, it sounds like you're allowing the user to enter a search expression. Then you're trying to act on search term by passing it directly into a regex function.
If a user enters N% expecting to look for an N followed by % any number of characters but the regex engine simply looks at the % character and tries to match it. You can correct the user provided search term by replacing the % with one of the following before using it as a regular expression:
.* greedy match all remaining characters on the line
.*? to non greedy match any number of characters
. to match any single character
The same would need to be done if the user entered a *.
Disclaimer: Depending on options used in the regex function . may or may not match new lines. Depending on your user base it might be better to simply tell users that the search term needs adhere to regular expression syntax. This would allow a knowledgeable user to build their own esoteric expressions.

RegEx to match comma separated numbers with optional decimal part

I've a regex that matches comma separated numbers with an optional two digit decimal part in a given multiline text.
/(?<=\s|^)\d{1,3}(,\d{3})*(\.\d{2})?(?=\s|$)/m
It matches strings like 1, 12, 12.34, 12,345.67 etc successfully. How can I modify it to match a number with only the decimal part like .23?
EDIT: Just to clarify - I would like to modify the regex so that it matches 12, 12.34 and .34
And I am looking for 'stand alone' valid numbers. i.e., number-strings whose boundaries are either white space or start/end of line/string.
This:
\d{1,3}(,\d{3})*(\.\d\d)?|\.\d\d
matches all of the following numbers:
1
12
.99
12.34
12,345.67
999,999,999,999,999.99
If you want to exclude numbers like 123a (street addresses for example), or 123.123 (numbers with more than 2 digits after the decimal point), try:
(?<=\s|^)(\d{1,3}(,\d{3})*(\.\d\d)?|\.\d\d)(?=\s|$)
A little demo (I guessed you're using PHP):
$text = "666a 1 fd 12 dfsa .99 fds 12.34 dfs 12,345.67 er 666.666 er 999,999,999,999,999.99";
$number_regex = "/(?<=\s|^)(?:\d{1,3}(?:,\d{3})*(?:\.\d\d)?|\.\d\d)(?=\s|$)/";
if(preg_match_all($number_regex, $text, $matches)) {
print_r($matches);
}
which will output:
Array
(
[0] => Array
(
[0] => 1
[1] => 12
[2] => .99
[3] => 12.34
[4] => 12,345.67
[5] => 999,999,999,999,999.99
)
)
Note that it ignores the strings 666a and 666.666
/(?<=\s|^)(\d{1,3}(,\d{3})*(\.\d{2})?|\.(\d{2}))(?=\s|$)/m
Or taking into account some countries where . is used as a thousand seperator, and , is used as a decimal seperator
/(?<=\s|^)(\d{1,3}(,\d{3})*(\.\d{2})?|\d{1,3}(\.\d{3})*(,\d{2})?|\.(\d{2})|,(\d{2}))(?=\s|$)/m
Insane Regex for Internationalisation
/((?<=\s)|(?<=^))(((\d{1,3})((,\d{3})|(\.\d{3}))*(((?<=(,\d{3}))(\.\d{2}))|((?<=(\.\d{3}))(,\d{2}))|((?<!((,\d{3})|(\.\d{3})))([\.,]\d{2}))))|([\.,]\d{2}))(?=\s|$)/m
Matches
14.23
14,23
114,114,114.23
114.114.114,23
Doesn't match
14.
114,114,114,23
114.114.144.23
,
.
<empty line>
This answer treats with this question more comprehensively.
(#"^((([0-9]+)(.([0-9]+))?)(\,(([0-9]+)(.([0-9]+))?))*)$")
This works for comma separated whole number or comma separated decimal numbers.
Example:
Happy scenarios:
case 1) 9,10
case 2) 10.1,11,12,15,15.2
case 3) 9.8
case 4) 9
Sad scenarios:
case 1) 2..7
case 2) 2,,7
case 3) 2.
case 4) 7,
case 5) ,
case 6) .
case 7) .2
case 8) ,2