3

I have written the following regex to match human-readable time at the command-line:

^(?:(?:(?:(\d+)d\s*)?(\d+)h\s*)?(\d+)m\s*)?(\d+)s$

Using non-capturing strings, this regex matches "human-readable" time equally-well in the following formats:

1d 2h 3m 4s
1h 2m 3s
1m 2s
1s

...and...

1d2h3m4s
1h2m3s
1m2s
1s

In this regex, if I include a minutes value, I also have to include a seconds value. I.e., I can't simply provide 15m or 1d3m, I have to provide 15m0s or 1d0h3m0s.

Is it possible to extend a regex to match these latter two use cases? How? Please note: I'm not necessarily looking for a drop-in solution, but a pointer in the right direction would be greatly appreciated.

Update

Just a brief update that I made awhile back - this is for regex in Python.

3
  • Which regex engine are you working with? Commented Sep 8, 2014 at 17:42
  • Apologies. I'm working with regex in Python. I was trying to ask it as a platform-agnostic question. Commented Sep 8, 2014 at 17:56
  • 2
    There is no language-agnostic regex, unfortunately. Commented Sep 8, 2014 at 17:57

4 Answers 4

2

You can use this pattern:

\A(?=\S)(?:\d+d)?(?:\h*\d+h)?(?:\h*\d+m)?(?:\h*\d+s)?\z

The approach is to make all element optional. The lookahead at the begining ensures that there is at least a character that is not a space. (in other words, it ensures that there is at least one element)

Sign up to request clarification or add additional context in comments.

7 Comments

why you use (?=\S) and not use (?=\S\S)
@walidtoumi: because testing two characters is useless, only one is necessary.
But the minimum is 1digit + 1letter (ex: 1s) ?
@walidtoumi:Indeed, but it doesn't matter, because once you know that there is at least one non-space character, you know that there is at least one group (whatever, the length of the group). The goal of the lookahead is only to check that the string is not empty since each group is optional. Its goal is not to test the length of the string but only to check that one group is present.
I played with this one. In Python, I wrote it as follows: ^(?=\S)(?:(?P<d>\d+)d\s*)?(?:(?P<h>\d+)h\s*)?(?:(?P<m>\d+)m\s*)?(?:(?P<s>\d+)s\s*)?$. It matches all possible combinations of day/hour/minute/second that I came up with, like so. Thanks!
|
2

Rather that maintaining that regular expression and trying to tweak it I would suggest greatly simplifying your regex to this:

/ *(\d+)([dhms])/gm

RegEx Demo

As you can see it matches all your current and proposed strings. You can then post-process both captured groups in your code.

Comments

1

your seconds files is not optional.there is no ? after it.so all fields not containg s will fail.

See demo.

http://regex101.com/r/iX5xR2/28

I have applied question mark.

6 Comments

Well, shucks. You mean it's that easy? I would have sworn I attempted exactly that regex without success. Just for the record (and future reference), the regex you threw out there was: ^(?:(?:(?:(\d+)d\s*)?(\d+)?h?\s*)?(\d+)m\s*)?((\d+)s)?$. Thanks.
@DarthBob you were very close.i just debugged your regex.it was nice.just a small change :)
No...I was wrong. As I looked at it, there are some differences between your regex and the one I tried. Thanks again!
So...here's something odd for you. In this section of your regex: (\d+)?h?\s*)?(\d+)m\s*), with the ? after the h, 15m matches with 1 in the hours position and 5 in the minutes position. If I remove the ? from after the h, 15m matches correctly, but 1d 5m no longer matches.
@DarthBob you have grouped d and h together.they were together in your regex.so to make h optional have to add that
|
0

You can use nested groups:

/^(?:(?:(?:(\d+)d\s*)?(\d+)h\s*)?(\d+)m\s*)?(\d+)s$/g

The value for d, h, m and s are in groups 1, 2, 3 and 4 respectively.

Here is a regex demo!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.