I'm looking for the most concise regex that matches one or two 4-digit years in any the following setups:
- year
- year-
- -year
- year-year
I can't think of anything slicker than this:
[\\-]?\d{4}|\d{4}\[\\-](\d{4})?
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It only takes a minute to sign up.
Sign up to join this communityI'm looking for the most concise regex that matches one or two 4-digit years in any the following setups:
I can't think of anything slicker than this:
[\\-]?\d{4}|\d{4}\[\\-](\d{4})?
I am assuming you prefer the longest match. That is, if the input line is:
xyzzy 2000-2010 xyzzy
then matching 2000
or 2010
or 2000-
or -2010
is not what you want, even though these would be valid matches the way you have stated the problem.
In Perl 5.10 and later, you can reduce the pattern to 20 characters:
(\d{4})-(?1)?|-?(?1)
Let's break this down.
(\d{4}) # match a year and capture the pattern
- # match a hyphen
(?1)? # match a year again if possible
| # OR,
-? # match an initial hyphen if possible
(?1) # match a year
Things get more complicated if you prefer to match two years even in cases such as:
xyzzy -2000-2010 xyzzy
See: http://perldoc.perl.org/perlretut.html#Recursive-patterns
This is a somewhat difficult one because regular expressions inherently lack memory, so you can't tell on the back whether the front existed, so I don't think one can get better than the one you wrote for that particular set. If you wanted to allow some sort of variant, you could potentially find a better one.
(?=.*\d)\d{4}?-\d{4}?
or even (abusing the fact the following pattern has only one false positive, a single dash) (?=..)\d{4}-\d{4}
.
\$\endgroup\$
If you first removed all "-" characters you could make it
(\d{4}){1,2}
or
(\d{4}|\d{8})