import re
regex = re.compile(r"(?<=\D|^)(?<year>\d{4})(?<sep>[^\w\s])(?<month>1[0-2]|0[1-9])\k<sep>(?<day>0[1-9]|[12][0-9]|(?<=11\k<sep>|[^1][4-9]\k<sep>)30|(?<=1[02]\k<sep>|[^1][13578]\k<sep>)3[01])(?=\D|$)", flags=re.MULTILINE)
test_str = ("\n"
"2020-01-01\n"
"2020-01-31\n"
"2020-02-29\n"
"2020-03-31\n"
"2020-04-30\n"
"2020-05-31\n"
"2020-06-30\n"
"2020-07-31\n"
"2020-08-31\n"
"2020-09-30\n"
"2020-10-31\n"
"2020-11-30\n"
"2020-12-31\n"
"2020-01-01 00:00:00,000\n"
"2020-01-01_00:00:00,000\n"
"2020-01-01-00:00:00,000\n"
"2020-01-01T00:00:00,000\n"
"2222-01-01\n"
"2222/11/22\n"
"2222.11.22\n\n"
"// Invalid dates\n"
"2020-00-01\n"
"2020-01-00\n"
"000-01-01\n"
"222-01-01\n"
"2020-1-1\n"
"2020-1-01\n"
"2020-01-1\n"
"2020-22-01\n"
"2020-01-33\n"
"2020-01-32\n"
"2020-02-30\n"
"2020-03-32\n"
"2020-04-31\n"
"2020-05-32\n"
"2020-06-31\n"
"2020-07-32\n"
"2020-08-32\n"
"2020-09-31\n"
"2020-10-32\n"
"2020-11-31\n"
"2020-12-32\n"
"a222-01-01\n"
"2a22-01-01\n"
"22a2-01-01\n"
"222a-01-01\n"
"2222-a1-01\n"
"2222-0a-01\n"
"2222-1a-01\n"
"2222-01-a1\n"
"2222-01-0a\n"
"2222-01-1a")
matches = regex.finditer(test_str)
for match_num, match in enumerate(matches, start=1):
print(f"Match {match_num} was found at {match.start()}-{match.end()}: {match.group()}")
for group_num, group in enumerate(match.groups(), start=1):
print(f"Group {group_num} found at {match.start(group_num)}-{match.end(group_num)}: {group}")
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Python, please visit: https://docs.python.org/3/library/re.html