1,468 bytes · the Python implementation · view raw
from .validation_bic_types import BicCheck
def _invalid(reason: str) -> BicCheck:
return BicCheck(
valid=False, normalised=None, institution=None, country=None, location=None, branch=None, reason=reason
)
def _is_upper(ch: str) -> bool:
return"A" <= ch <= "Z"def validate_bic(value: str) -> BicCheck:
"""Check the format of a BIC and split it into institution, country, location and branch. Well formed is not registered: only SWIFT's directory knows whether the code is assigned. Validators answer rather than raise. """ifnot isinstance(value, str):
return _invalid("empty")
# Folded by hand: str.upper() is Unicode-aware and Rust's ASCII fold is not.
bic = "".join(chr(ord(ch) - 32) if"a" <= ch <= "z"else ch for ch in value if ch != " ")
ifnot bic:
return _invalid("empty")
if any(not (_is_upper(ch) or"0" <= ch <= "9") for ch in bic):
return _invalid("bad-character")
if len(bic) != 8and len(bic) != 11:
return _invalid("bad-length")
ifnot _is_upper(bic[4]) ornot _is_upper(bic[5]):
return _invalid("bad-country")
return BicCheck(
valid=True,
normalised=bic,
institution=bic[0:4],
country=bic[4:6],
location=bic[6:8],
# An 8-character BIC is the primary office, which the 11-character form spells XXX.
branch=bic[8:11] if len(bic) == 11else"XXX",
reason=None,
)