What is the difference between re.search and re.match?

Short answer

re.match only matches at the beginning of the string. re.search finds the pattern anywhere. If your pattern "does not work", you almost certainly wanted search.

python
import re
text = "Contact Dom at dom@example.com"

re.match(r"Dom", text)     # None  — 'Dom' is not at position 0
re.search(r"Dom", text)    # <re.Match object>
re.match(r"Contact", text) # <re.Match object>

The name is the trap. "Match" sounds like the general operation; it is actually the anchored one.

#The four functions

FunctionFinds
re.searchThe first match anywhere
re.matchA match at the start only
re.fullmatchOnly if the whole string matches
re.findallEvery match, as a list of strings

re.finditer is the lazy version of findall, yielding match objects instead of strings.

#For validation, anchor explicitly

python
EMAIL = r"^[\w.+-]+@[\w-]+\.[\w.]+$"
bool(re.match(EMAIL, candidate))

The ^ and $ matter even with match: without $, "dom@x.co and more junk" would pass, because match only requires the start to line up.

re.fullmatch does the same job without needing the anchors.

#Always use raw strings

Write r"\d+", not "\d+". Without the r, Python processes the backslash first and hands the regex engine something you did not write.