This regular expression validates timestamps e.g. 2018-02-12 00:55:22:
[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9]
However, the timestamp should be validated step by step:
201 => true
201a => false
2018- => true
20189 => false
Is there a nice (short) regex extension?
......
Because your question has the javascript tag I am going to assume you are doing "step-by-step" validation like "onkeyup" or similar. The following pattern will validate your datetime string as it is being constructed (I'm including an empty string as valid so that no flag is triggered when empty; but you could change to \d{1,4} if you want to act on empty strings).
I am using \d whenever possible to reduce pattern length.
The x pattern modifier is in play with my dumped pattern, for easier reading. When you apply this to your project, you can compact it all and remove the x flag.
I am using non-capturing groups out of habit; since you are probably only matching, you can use capturing groups if you like.
Pattern Demo
Pattern:
~
^
(?:
\d{0,4}|
\d{4}-|
\d{4}-[01]|
\d{4}-(?:0[1-9]|1[0-2])|
\d{4}-(?:0[1-9]|1[0-2])-|
\d{4}-(?:0[1-9]|1[0-2])-[0-3]|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s[0-2]|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d)|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):[0-5]|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):[0-5]\d|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):[0-5]\d:|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):[0-5]\d:[0-5]|
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])\s(?:2[0-3]|[01]\d):[0-5]\d:[0-5]\d
)
$
~
x
You can combine it to get 2 overall information blocks.
Incrementally match the form delimiters - - : :
while allowing/matching bad segments.
In the end you get info on the form progress.
And also the form segments.
You test the form's progress via capture groups 2,4,6,8,10
You test the date/time elements via groups 1,3,5,7,9,11
Though, you only need to test the elements up to the maximum group in the form
progress.
^(?:(?:([0-9]{4})|\d*)(-(?:(0[1-9]|1[0-2])|\d*)(-(?:(0[1-9]|[1-2][0-9]|3[0-1])|\d*)([ ]+(?:(2[0-3]|[01][0-9])|\d*)(:(?:([0-5][0-9])|\d*)(:(?:([0-5][0-9])|\d*))?)?)?)?)?)$
Formatted
^
(?:
(?:
( [0-9]{4} ) # (1)
| \d*
)
( # (2 start)
-
(?:
( 0 [1-9] | 1 [0-2] ) # (3)
| \d*
)
( # (4 start)
-
(?:
( 0 [1-9] | [1-2] [0-9] | 3 [0-1] ) # (5)
| \d*
)
( # (6 start)
[ ]+
(?:
( 2 [0-3] | [01] [0-9] ) # (7)
| \d*
)
( # (8 start)
:
(?:
( [0-5] [0-9] ) # (9)
| \d*
)
( # (10 start)
:
(?:
( [0-5] [0-9] ) # (11)
| \d*
)
)? # (10 end)
)? # (8 end)
)? # (6 end)
)? # (4 end)
)? # (2 end)
)
$
segments via if the capture groups matched.
Regex is not the way to do this.
Heres a simple function. You use a good date in the correct format, strip off the number of characters from the front that have been entered and combine it with the vale entered, then check if its valid
function validateDate($date)
{
$fakedate = "2018-02-12 00:55:22";
$date .= substr($fakedate, strlen($date));
$format = 'Y-m-d H:i:s';
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
var_dump(validateDate('201')); bool(true)
var_dump(validateDate('201a')); bool(false)
var_dump(validateDate('2018-')); bool(true)
var_dump(validateDate('20189')); bool(false)
Related
This question already has answers here:
Regular expression to stop at first match
(9 answers)
Closed 2 years ago.
I have this test string, which I want to extract data from using Regex:
"-> Single-row index lookup on using <auto_distinct_key> (actor_id=actor.actor_id) (cost=901.66 rows=5478) (actual time=0.001..0.001 rows=0 loops=200)"
The six fields of data that I want to extract are written in bold. The segment that is written in italic is the optional part of the statement.
This is the pattern which I have arrived at thus far:
-> (.+) (\(cost=([\d\.]+) rows=(\d+)\))? \(actual time=([\d\.]+) rows=(\d+) loops=(\d+)\)
This gives me six groups with all the data I want. However, when I omit the optional part of the string it does not match at all. I suspected this was due to superfluous whitespaces, so I thought it might work to move the whitespace into the optional group, like this:
-> (.+)( \(cost=([\d\.]+) rows=(\d+)\))? \(actual time=([\d\.]+) rows=(\d+) loops=(\d+)\)
Which did not work.
It seems to match the optional group as part of the first group, which is not really what I want. I want them separate, and I'm not quite sure how to do that.
You have to make the first (.+) lazy quantifier (.+?)
https://regex101.com/r/fbE0tW/1
# (.+?)[ ]?((?<=[ ])\(cost=([\d\.]+)[ ]rows=(\d+)\))?[ ]\(actual[ ]time=([\d\.]+)[ ]rows=(\d+)[ ]loops=(\d+)\)
( .+? ) # (1)
[ ]?
( # (2 start)
(?<= [ ] )
\( cost=
( [\d\.]+ ) # (3)
[ ] rows=
( \d+ ) # (4)
\)
)? # (2 end)
[ ]
\(
actual [ ] time=
( [\d\.]+ ) # (5)
[ ]
rows=
( \d+ ) # (6)
[ ]
loops=
( \d+ ) # (7)
\)
I want to find 10 digit numbers with no repeat digits, for example:
1123456789 //fail, there are two 1's
6758951230 //fail, there are two 5's
6789012345 //pass, each digit occurs once only.
at the moment I am using regex but can only match 10digits numbers(it doesnt check for duplicates. I am using this regex:
[0-9]{10}
Can this be done with regex or is there a better way to achieve this?
This regex works:
^(?!.*(.).*\1)\d{10}$
This uses an anchored negative look ahead with a back reference to assert that there are no repeating characters.
See a live demo working with your examples.
In java:
if (str.matches("^(?!.*(.).*\\1)\\d{10}"))
// number passes
Try this one (?:([0-9])(?!.*\1)){10}, this will work if you're validating numbers one at a time.
This should work (?:([0-9])(?!\d*\1)){10} to search for each occurance of an unique 10-digit sequence, but it will fail with 12345678901234567890, will find the last valid part 1234567890 instead of ignoring it.
Source and explanations: https://stackoverflow.com/a/12870549/1366360
Here's the shortest and efficient regex with less backtracking due to the presence of a ?.
Works for any length of input:
!/(.).*?\1/.test(number)
Examples:
!/(.).*?\1/.test(1234567890) // true
!/(.).*?\1/.test(1234567490) // false - note that it also works for repeated chars which are not adjacent.
Demo
- checks for repeated digits
- opposite of what you want, because rubular doesn't allow a !
lancemanfv regex reference https://stackoverflow.com/a/12870549/1366360 is a great one, but the suggested regex is slightly off.
Instead try
^(?:([0-9])(?!.*\1)){10}$
This will match any string that begins and ends with 10 digits that are all different.
If you want to check (and extract) if a longer string contains a 10 digit number with each number different use this
((?:([0-9])(?!.*\2)){10})*
You can then use a numbered reference to extract the matching number
Works every time (I see this question) -
Revised to define Grp 10 before the (?! \10 ) assertion. \1-\9 are always considered backrefs (> \10, the parenth's must be before it is referenced).
So made them all the same as well.
Note- this can be used to find a floating (substring) 10 uinque digit number. Requires no anchors.
Fyi - With Perl, the \g{#} (or \k'name') syntax could be used before the group is defined, no matter what number the group number is.
# "(?:((?!\\1)1)|((?!\\2)2)|((?!\\3)3)|((?!\\4)4)|((?!\\5)5)|((?!\\6)6)|((?!\\7)7)|((?!\\8)8)|((?!\\9)9)|((?!\\10)0)){10}"
(?:
( # (1)
(?! \1 )
1
)
| ( # (2)
(?! \2 )
2
)
| ( # (3)
(?! \3 )
3
)
| ( # (4)
(?! \4 )
4
)
| ( # (5)
(?! \5 )
5
)
| ( # (6)
(?! \6 )
6
)
| ( # (7)
(?! \7 )
7
)
| ( # (8)
(?! \8 )
8
)
| ( # (9)
(?! \9 )
9
)
| ( # (10)
(?! \10 )
0
)
){10}
I want to capture all numbers(any no.of digits) except the 10 digit numbers starting with 7.
71234567890 - should match
7123456789 - should not match
1234567890- should match
Use the pattern
/7\d{9}|(\d+)/
^^^^^^ MATCH 10-DIGIT NUMBER STARTING WITH SEVEN, DO NOT CAPTURE
^ --OR--
^^^^^ MATCH OTHER SEQUENCES OF DIGITS AND DO CAPTURE
This will match the 10-digit number starting with 7 but not capture it; otherwise, it will match the sequence of digits and capture it.
Now
'7123456789'.match(regexp)
["7123456789", undefined]
'1234567890'.match(regexp)
["1234567890", "1234567890"]
In other words, the captured string will be found in the second element of the array returned by match.
If you want to anchor this to the beginning and end of the string, then
/^7\d{9}$|(^\d+$)/
You could also do this with a negative look-ahead, as suggested in the comments, but it's not needed here and could be a bit of a stretch for beginning regexpers.
(?:(?:^|\D)(7\d{1,8}|7\d{10,})(?:\D|$))
See the DEMO
In order to get any number of digits except a string of 10 digits starting with '7'
you'd have to special case the '7'. There is really no way around it.
The fastest way is a pure regex solution, since the engine stays inside
running c++ engine code and does not interact with the host language.
There are two ways, either anchored or mid-string.
Anchored: ^(?:7(?!\d{9}$)|[012345689])\d*$
(number string is the overall match, i.e. in capture group 0)
^ # Beginning of string
(?: # Cluster, get first digit
7 # '7'
(?! \d{9} $) # not followed by nine more digits
| # or
[012345689] # Any digit except '7' (i.e. [^\D7])
) # End cluster
\d* # Get optional remaining digits
$
Mid-string: (?:^|\D)((?:7(?!\d{9}(?:\D|$))|[012345689])\d*)
(number string is in capture group 1)
(?: ^ | \D ) # Beginning of string or not a digit
( # (1 start), The number
(?: # Cluster, get first digit
7 # '7'
(?! # Assertion, not followed by nine more digits
\d{9}
(?: \D | $ ) # (forces no more/less than nine) digits
)
| # or
[012345689] # Any digit except '7' (i.e. [^\D7])
) # End cluster
\d* # Get optional remaining digits
) # (1 end)
Hello I wanted to do autofiller to match to this format "HH:MM".
I wanted to check only against this regex /^(0[1-9]|1[012]):[0-5][0-9]$/ but have no idea how to match regex substring. I've looked at wikipedia and some sites and can't find modificator to check for 'subregex'. Doesn't this option exist? I've finally solved this problem with code below, but this array could certainly be generated programmatically, so there should already be solution I am searching for. Or it doesn't exist and I should write it?
patterns = [ /./, /^[0-9]$/, /^(0?[1-9]|1[012])$/, /^(0[1-9]|1[012]):$/, /^(0[1-9]|1[012]):[0-5]$/, /^(0[1-9]|1[012]):[0-5][0-9]$/]
unless patterns[newTime.length].test(newTime)
newTime = newTime.substring(0, newTime.length - 1)
You could probably accomplish the same thing a bit more efficient.
Combine the regexes into a cascading optional form, then use the match length, substring
and a template to auto complete the time.
Pseudo code (don't know JS too well) and real regex.
# pseudo-code:
# -------------------------
# input = ....;
# template = '00:00';
# rx = ^(?:0(?:[0-9](?::(?:[0-5](?:[0-9])?)?)?)?|1(?:[0-2](?::(?:[0-5](?:[0-9])?)?)?)?)$
# match = regex( input, rx );
# input = input + substr( template, match.length(), -1 );
^
(?:
0
(?:
[0-9]
(?:
:
(?:
[0-5]
(?: [0-9] )?
)?
)?
)?
|
1
(?:
[0-2]
(?:
:
(?:
[0-5]
(?: [0-9] )?
)?
)?
)?
)
$
I'm trying to make a simple regex expression to match simple URLs (without URL parameters etc.)
it seems to work but there is still some problem..
This is my regex:
/(https|http|ftp):\/\/((-|[a-z0-9])+\.)+(com|org|net)\/?((-|[a-z0-9]\/?)+(-|[a-z0-9])*\.(css|js))?/ig
In this little list you can see what does not work properly:
HTTP://q-2Ud.a.q-2Ud.com/
https://q-2Ud.q-2Ud.q-2Ud.com
http://www.q-2Ud.q-2Ud.q-2Ud.com
http://www.q-2Ud.q-2Ud.q-2Ud.com/c ------------------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/cs -----------------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/css ----------------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/csss ---------------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/csss/css -----------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/css/yuyuyu/gyygug.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/h/.css -------------------------------> NOT WORK
http://www.q-2Ud.q-2Ud.q-2Ud.com/.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/k.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/kk.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/kkk.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/f-1.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/o/o.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/d-1/d-2/d-3/d-4/f-1.css
http://www.q-2Ud.q-2Ud.q-2Ud.com/q-2Ud/q-2Ud/q-2Ud/q-2Ud/q-2Ud.js
Demo Here
it is matching URLs with .css or .js ending.
Remove \.(css|js) and it should work
/(https|http|ftp):\/\/((-|[a-z0-9])+\.)+(com|org|net)\/?\.?((-|[a-z0-9]\/?)+(-|[a-z0-9])*\/?(\.css|\.js)?)?/ig
This may catch all the ones that you are missing
Just need to arrange the groups a little better while maintaining validity.
This is trimmed to capture just the main 4 parts without delimiters.
edit: If you don't want to match .js or .css without a filename, use this regex ->
(?i)(https|http|ftp)://((?:[a-z0-9-]+\.)+(?:com|org|net))(?:/(?:([a-z0-9-]+(?:/?[a-z0-9-])*(?:\.(css|js))?))?)?
otherwise use this one ->
# /(?i)(https|http|ftp):\/\/((?:[a-z0-9-]+\.)+(?:com|org|net))(?:\/(?:([a-z0-9-]+(?:\/?[a-z0-9-])*)\/?)?(?:\.(css|js))?)?/
(?i)
( https | http | ftp ) # (1)
://
( # (2 start)
(?:
[a-z0-9-]+
\.
)+
(?: com | org | net )
) # (2 end)
(?:
/
(?:
( # (3 start)
[a-z0-9-]+
(?:
/?
[a-z0-9-]
)*
) # (3 end)
/?
)?
(?:
\.
( css | js ) # (4)
)?
)?