-1

Hey I have a working regex that really does the job it should.

One thing I would like to add or change is that the min Value should be 00:01 not 00:00.

Here is the ReGex I am using: let regexTime = /^$|^(([01][0-9])|(2[0-3])):[0-5][0-9]$/;

Basically only Time from 00:00 to 23:59 is allowed. But I need to have it that it starts from 00:01.

Is this possible I guess I cant just stay that the last number must be over 1 because obviously 00:10 should also be possible.

Thanks for any advice!

yesIamFaded
  • 1,970
  • 2
  • 20
  • 45
  • `regex` is a powerful tool but it is not appropriate for what you want. Use the regex to check the shape of the input string (it should match `^\d\d:\d\d$`) then use the functions provided by the language to split the string into components and analyze them (hours between `0` and `23`, minutes between `0` and `59`) and the relations between them (hours and minutes cannot be `0` on the same time etc). – axiac Sep 18 '20 at 07:22
  • I feel that you want answers within regex, instead of the easier way of doing it in the programming language. If I am right please explain that and the reasons. – Yunnosch Sep 18 '20 at 07:22
  • @axciac Your comment seems to echo the answer by jeremy (though more abstract). If not please consider making your own answer to make the difference more obvious. – Yunnosch Sep 18 '20 at 07:24
  • I mean I honestly want to know if it would be possible to do with regex like a build in if in regex kinda like that. But I guess I could do it programmatically wich would not cause a problem in my app. I just was curious if regex could handle this case :) – yesIamFaded Sep 18 '20 at 07:24
  • Yes, I thought so. Please explain that by [edit]ing your question. But please take care not to fundamentally change the question, i.e. make sure that the answer given below stays valid. – Yunnosch Sep 18 '20 at 07:26

3 Answers3

0

00:00 is one special case. Exclude it before running your regex, that's it.

if( thingToTest === "00:00" ){
   return;
}

regexTime.test(thingToTest);
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • Either you are right (and deserve my upvote), or you will provoke OP into explaining why this is not what they are asking for (for which you can also have my upvote). Because I think they want to learn about the (tedious) ways of doing it within the regex. – Yunnosch Sep 18 '20 at 07:21
  • Haha thanks :) I think that's an XY problem. OP _wants_ the regex to start at a minimum, because they think it's the only way to solve the problem, so they're stuck and ask how to do it on SO. Instead of pulling my hair out and coming up with a super complicated regex, I solved the problem in a different way. That's what I'd do in real life conditions. – Jeremy Thille Sep 18 '20 at 07:27
  • I know that I can do it like that - just wanted to see the power of regex handle it or if it can handle it ;) – yesIamFaded Sep 18 '20 at 07:29
  • (Jeremy) And it is the right way to go about it to solve a given problem, hence my upvote. Seeing OPs comments they even agree, but want to learn. I tried to protect you from harm due to a possible "moving target" question, because you might blame me if it turns into one... Consider adapting to what OP actually wants... Have fun. – Yunnosch Sep 18 '20 at 07:30
  • I had left a comment saying "thank you, nice move", and apparently it was removed by the god of moderation. I didn't know saying thank you was an outrage on SO. – Jeremy Thille Sep 21 '20 at 07:37
0

Use a negative lookahead to prevent the 00:00 specific case:

^$|^(?!00:00$)(([01][0-9])|(2[0-3])):[0-5][0-9]$

Demo: https://regex101.com/r/jSKyZN/2

Vincent
  • 3,945
  • 3
  • 13
  • 25
0

There is no concept for "minimum value" of a regex, since it's only doing pattern matching, not reasoning about what the pattern represents. However, you can just exclude a certain pattern from being matched. If you don't want 00:00 then you can remove that from being valid.

Negative lookahead

The easiest way to modify your regular expression is to add a negative lookahead using the (?!) syntax. If you don't want to match 00:00 then you can say (?!00:00). Your regular expression then needs to be:

^$|^(?!00:00)(([01][0-9])|(2[0-3])):[0-5][0-9]$

See on Regex101

const regex = /^$|^(?!00:00)(([01][0-9])|(2[0-3])):[0-5][0-9]$/;

const times = [
  "00:01",
  "00:10",
  "01:00",
  "12:01",
  "13:01",
  "23:59",
  "00:00",
  "23:60",
  "24:00",
];

for (const time of times) {
  test(time, regex);
}

function test(time, regex) {
  const result = regex.test(time);
  
  console.log(`result for [${time}] is [${result}]`);
}

Non-matching pattern

You can alternatively craft your pattern to avoid matching 00:00 outside of using negation. This is slightly more tedious as it makes the pattern bigger. Still, it's useful to know:

(([01][0-9])|(2[0-3])):[0-5][0-9] will match anything and to avoid 00:00 you have to be very explicit by specifying anything but a pattern than matches it:

^$|^(00:0[1-9]|00:[1-5][0-9]|0[1-9]:[0-5][0-9]|(1[0-9]|2[0-3]):[0-5][0-9])$

See on Regex101

Now the pattern explicitly matches everything except 00:00. As you see, it's quite longer and more annoying to read. I wouldn't recommend it but it's sometimes useful.

const regex = /^$|^(00:0[1-9]|00:[1-5][0-9]|0[1-9]:[0-5][0-9]|(1[0-9]|2[0-3]):[0-5][0-9])$/;

const times = [
  "00:01",
  "00:10",
  "01:00",
  "12:01",
  "13:01",
  "23:59",
  "00:00",
  "23:60",
  "24:00",
];

for (const time of times) {
  test(time, regex);
}

function test(time, regex) {
  const result = regex.test(time);
  
  console.log(`result for [${time}] is [${result}]`);
}

The best regex trick

This is the name of the technique from the article The Best Regex Trick. It's similar to using a negative lookahead since it allows you to discard certain matches but it's done only using alternation |. You have to add the pattern(s) you don't want first then | then finally capture the pattern you want using a capturing group ().

^$|^00:00$|^((?:[01][0-9]|2[0-3]):[0-5][0-9])$

See on Regex101 (00:00 is highlighted but not captured - see "Match information" on the right)

I've modified your pattern slightly to remove unneeded capturing groups, so you only get a single capture at most. This way you can check whether that was extracted:

const regex = /^$|^00:00$|^((?:[01][0-9]|2[0-3]):[0-5][0-9])$/;

const times = [
  "00:01",
  "00:10",
  "01:00",
  "12:01",
  "13:01",
  "23:59",
  "00:00",
  "23:60",
  "24:00",
];

for (const time of times) {
  test(time, regex);
}

function test(time, regex) {
  const match = regex.exec(time);
  const result = Boolean(match && match[1]);
//                             ^^ you can use the ?? operator for most newer environments *
  
  console.log(`result for [${time}] is [${result}]`);
}

This is a slight overkill here because the negative lookahead can do the same. I'm including it here mostly to raise awareness of its existence. The technique is very useful in other circumstances where you need to only match some cases but not all, since it allows you to "discard" what you don't like and capture the rest. It's exceptionally easy, since it follows a very simple rule discard this|discard this, too|(keep this) - anything you don't want is added at the front, and the pattern you want is in a capturing group at the end.

Use code

You can just reject data using normal code, rather than pattern matching.

const regex = /^$|^(([01][0-9])|(2[0-3])):[0-5][0-9]$/;

const times = [
  "00:01",
  "00:10",
  "01:00",
  "12:01",
  "13:01",
  "23:59",
  "00:00",
  "23:60",
  "24:00",
];

for (const time of times) {
  test(time, regex);
}

function test(time, regex) {
  let result = false;
  if (time != "00:00") {
    result = regex.test(time);
  }
  
  console.log(`result for [${time}] is [${result}]`);
}
VLAZ
  • 26,331
  • 9
  • 49
  • 67