Sort messages into categories
Support teams route messages by the words in them. A function that cleans the text, checks keyword lists in priority order and returns one category turns that rule into code.
- Clean text with
lowerandstripbefore matching keywords - Check categories in a fixed priority order and return the first match
- Combine several signals (keywords, a flag) into one decision
The CFPB publishes consumer complaints with a free-text narrative. Before anyone reads them, a first pass routes each one to a team: fraud, billing, account access. The rule is simple: clean the text, then check each category's keywords in priority order; the first category with a matching keyword wins. Fraud is checked first because a message that mentions both a fee and a stolen card must go to fraud.
A list of (category, keywords) tuples keeps that order explicit, and changing the rules means editing data, not code.
Run each example to see what it prints. Running examples doesn't count toward progress.
RULES = [
("fraud", ["unauthorized", "stolen", "scam"]),
("billing", ["fee", "charge", "refund"]),
("access", ["locked", "password", "log in"]),
]
def categorize(message):
"""Return the first category whose keyword appears in the message, or "other"."""
text = message.lower()
for category, keywords in RULES:
for word in keywords:
if word in text:
return category
return "other"
print(categorize("I was charged a late FEE twice"))
print(categorize("There is an unauthorized charge on my card"))
print(categorize("Can't LOG IN since the update"))
print(categorize("Please update my mailing address"))Keyword matching with in finds text inside other text: "fee" is in "feedback". Real routers accept that trade-off for a first pass, but they add other signals so one word doesn't decide everything. Here a priority depends on both the words and whether the customer is flagged as vulnerable, and the result is a tuple so the caller gets both answers.
URGENT = ["stolen", "unauthorized", "locked out"] def triage(message, vulnerable=False): text = message.strip().lower() hits = 0 for word in URGENT: if word in text: hits = hits + 1 if hits >= 2 or (hits == 1 and vulnerable): priority = "high" elif hits == 1: priority = "medium" else: priority = "low" return priority, hits print(triage("Card STOLEN and unauthorized withdrawals")) print(triage("I am locked out of online banking", vulnerable=True)) print(triage(" Locked out again ")) print(triage("Question about statement dates"))
When to use it: first-pass routing, tagging and filtering of text. Mistakes to avoid:
- Matching before cleaning:
"FEE"is not"fee". - Checking categories in the wrong order, so a low-priority category catches messages first.
- Forgetting that
inmatches part of a word; choose keywords long enough to be specific.
- Clean the text, then check keyword lists in priority order and return the first match.
- Keep rules as data: a list of (category, keywords) tuples.
inmatches inside words; combine several signals when one word shouldn't decide.- Next: a complete small program built from functions that each do one step.