Matching
Matching¶
Exact, by default¶
The default is pycountry.countries.lookup: case-insensitive, across every field the standard indexes, and nothing else. It is accent-sensitive, because pycountry's indices are — "CÔTE D'IVOIRE" resolves and "Cote d'Ivoire" does not.
Numeric codes are three digits wide and the leading zero is part of the value, so an integer column needs padding before it will match:
Fuzzy matching¶
fuzzy=True lets an exact miss fall back to pycountry's search_fuzzy, which folds accents away, matches partial names and initials, and reaches countries through their subdivisions:
pc.alpha_2("country", fuzzy=True)
# "Cote d'Ivoire" -> CI (accents folded)
# "USA" -> US (initials of "United States of America")
# "Texas" -> US (via the subdivision)
# "Bavaria" -> null (the standard says "Bayern"; this is not a translation layer)
It is off by default because it is a guess, and a wrong guess is harder to notice than a null. "Republic of Korea" resolves to KP, not KR — no ISO field spells the name that way, so the subdivision pass decides it. pycountry answers KP too; the point is that fuzzy answers deserve review, which is what pc.match is for:
df.with_columns(pc.match("country", fuzzy=True).alias("m")).unnest("m")
# matched_on: "alpha_3", "name", "numeric", ... or "fuzzy"
# score: null for an exact match; the fuzzy points otherwise
Filtering on pl.col("score").is_null() separates the answers you can trust from the ones worth eyeballing.
One deliberate divergence: pycountry.countries.search_fuzzy("") matches every country — the empty string is a substring of every name, at offset 0 — and ranks Andorra first. In a DataFrame that turns every blank cell into a confident wrong answer, so blank input is null here.
Historic countries — ISO 3166-3¶
historic=True consults the withdrawn-country table when ISO 3166-1 has no match. Current countries always win, so a reused code like AI still resolves to Anguilla rather than to French Afars and Issas:
pc.extract("country", historic=True)
# "YUCS" -> alpha_2 YU, withdrawal_date 2003-07-23, historic true
alpha_4 and withdrawal_date are ISO 3166-3 fields, so they are populated only for a historic match. They are in the struct either way — a keyword never changes its shape.