Column Matching¶
xlea supports four strategies for matching a column descriptor to a header
cell. All strategies are set via the pattern argument of
Column().
Exact string match¶
The simplest case — the pattern must equal the header value exactly:
class Report(Schema):
total: float = Column("Total (USD)")
Case-insensitive match¶
Pass ignore_case=True to match regardless of casing:
class Report(Schema):
name: str = Column("client name", ignore_case=True)
# matches: "Client Name", "CLIENT NAME", "client name", …
Note
ignore_case has no effect when the pattern is a compiled
re.Pattern. Apply flags directly to the pattern instead:
re.compile(r"name", re.IGNORECASE).
Regular expression¶
Pass a compiled re.Pattern or set regexp=True on a string:
import re
from xlea import Schema, Column
class Sales(Schema):
# Compiled pattern — re.IGNORECASE applied directly
revenue: float = Column(re.compile(r"revenue", re.IGNORECASE))
# String + regexp=True — compiled without flags
units: int = Column(r"^Units\s*\(.*\)$", regexp=True)
The pattern is matched with re.search(), so it can match anywhere
in the header value unless anchored with ^ / $.
Callable predicate¶
For full control, pass any callable that takes a str and returns bool:
class Forecast(Schema):
q1: float = Column(lambda h: h.startswith("Q1"))
q2: float = Column(lambda h: h.startswith("Q2"))
# or with a named function for clarity:
def is_revenue_col(header: str) -> bool:
return "revenue" in header.lower() and "net" not in header.lower()
class Report(Schema):
revenue: float = Column(is_revenue_col)
Combining strategies¶
Different columns in the same schema can use different strategies:
import re
from xlea import Schema, Column
class Invoice(Schema):
id: int = Column("Invoice ID") # exact
client: str = Column("client", ignore_case=True) # case-insensitive
amount: float = Column(re.compile(r"amount", re.I)) # regex
note: str = Column(lambda h: "note" in h.lower(), # callable
required=False, default="")