I'm attempting to ensure a Regex matching pattern works well for all astronomical declinations between -90 and 90 degrees.
I'm using a matching pattern as follows:
^(?:(?:[ -]?([0-8]?\d|2[0-9])[°:\s])\s?\s?([0-5]?\d)[\':\s]?)\s?([0-5]?\d).?([0-9]?\d{1,9})[\"]?$
I have added some strings that I wish to fail and succeed here:
https://regex101.com/r/Z0Kf6I/1
I have almost got it, but I'm struggling how to allow for the following strings which I want to be matched but are currently not:
90°00'00.00" => Succeed, but failing
90:00:00.00 => Succeed, but failing
90:00:00.00 => Succeed, but failing
-90:00:00.00 => Succeed, but failing
90°00'00.00" => Succeed, but failing
-90°00'00.00" => Succeed, but failing
90 0 0.00 => Succeed, but failing
Essentially, this is because I have a match for a single character present in the list below [0-8]
. But changing this to [0-9]
will obviously then allow values greater than 90, e.g., 91,92, etc but these should fail.
Any pro Regex tips on how to achieve this would be greatly appreciated!
It looks like I can get a little closer with this regex:
^(?:(?:[ -]?([0-8]?\d|90)[°:\s])\s?([0-5]?\d)[\':\s]?)\s?([0-5]?\d)\.(\d{1,9})[\"]?
CodePudding user response:
I'd treat the case where it's exactly 90 separately, like so:
^[ -]?(?:[0-8]\d|\d)[°: ]?\s*?\d\d?[': ]\s*?\d\d?\.\d \"?|^[ -]?90[°: ]\s*?00?[': ]\s*?00?\.0 \"?
https://regex101.com/r/wByk9t/1
CodePudding user response:
I would avoid interpreting numbers in regex, not necessarily because it's impossible, but because it's harder to read and maintain. You can match with the following regex:
([ -]?\d )([°: ])(\d )([': ])(\d [.]\d*)("?)
Now you can just convert groups 1, 3, 5 into a number and check if it is > 90. You can also check if the separators in groups 2, 4, 6 are matching or not.
CodePudding user response:
My understanding is that 90 is the maximum, so if the first number is 90 then any following must be zero. In that case, simply set the 90 and all zero case as an alternative:
^(?:[ -]?(90)[°:\s]\s*(0 )[\':\s]?\s*(0 )\.(0 )[\"]?|[ -]?([0-8]?\d)[°:\s]\s*([0-5]?\d)[\':\s]?\s*([0-5]?\d)\.(\d )[\"]?)
https://regex101.com/r/Z0Kf6I/4
With some explanation, suitable for Perl or Python with the x
flag:
^ # start of line
(?:
[ -]?(90)[°:\s] # 90 degrees with optional unit or separator
\s*
(0 )[\':\s]? # 0 minutes with optional unit or separator
\s*
(0 )\.(0 )[\"]? # 0.0 seconds with optional unit
| # OR
[ -]?([0-8]?\d)[°:\s] # 0-89 degrees with optional unit or separator
\s*
([0-5]?\d)[\':\s]? # 0-59 minutes with optional unit or separator
\s*
([0-5]?\d)\.(\d )[\"]? # 0-59 seconds with optional unit
)
But as I said in comments, this is better accomplished with whatever language you're using. Split it on the possible separators and then do whatever checks your logic dictates. It is easier to understand and maintain code than regular expressions.
CodePudding user response:
You can use
^[ -]?([0-8]?\d|90(?=(?:\D*0)*\D*$))[°:\s]\s{0,2}([0-5]?\d)[':\s]?\s?([0-5]?\d).?(\d{1,10})\"?
See the regex demo.
Details:
^
- start of string[ -]?
- an optional-
or([0-8]?\d|90(?=(?:\D*0)*\D*$))
- Group 1: an optional digit from0
to8
and then any one digit, or90
that is immediately followed with zero or more repetitions of any non-digit char followed with a0
char, and then any non-digit chars till end of string[°:\s]
-°
,:
or a whitespace\s{0,2}
- zero, one or two whitespaces([0-5]?\d)
- Group 2: an optional digit from0
to5
range and then one digit[':\s]?
- an optional'
,:
and whitespace\s?
- an optional whitespace([0-5]?\d)
- Group 3: an optional digit from0
to5
range and then one digit.?
- any optional char other than line break chars(\d{1,10})
- Group 4: one to ten digits\"?
- an optional"
char.