Untitled
Anonymous
plain_text
02/26/2026 1:31 PM
82.6 KB
16
Indexable
import re # Import regex module for pattern matching in text
from typing import Optional, List # Import type hints for better code documentation
from peopleToMongoDB.personLoader.constants.allowedRoleExceptions import ALLOWED_ROLE_EXCEPTIONS
# python -m peopleToMongoDB.personLoader.utils.roleNormalizer
class RoleNormalizer:
"""
This class takes messy job titles and converts them into clean, standardized formats.
For example:
- "Chief Executive Officer" becomes "CEO"
- "VP of Sales and Marketing" becomes ["VP"]
- "Assistant to the CEO" becomes None (filtered out as support role)
The main goal is to identify executive and leadership roles while filtering out
support staff, assistants, and junior positions.
"""
def __init__(self):
"""
This method runs when we create a new RoleNormalizer object.
It sets up all the rules and patterns we'll use to normalize job titles.
"""
# List of words/phrases that indicate support or lower-level roles
# These will cause a title to be filtered out (rejected)
# \b means "word boundary" - ensures we match whole words, not parts of words
self.exclusion_patterns = [
r'\bintern\b', # Matches "intern" but not "internal"
r'\btrainee\b', # Matches "trainee"
r'\bjunior\b', # Matches "junior"
r'\bdeputy\b', # Matches "deputy"
r'\bassociate\b', # Matches "associate"
r'\baide\b', # Matches "aide"
r'\bcoordinator\b', # Matches "coordinator"
r'\bpa\b', # Matches "PA" (Personal Assistant)
r'\bpersonal assistant\b', # Matches "personal assistant"
r'\boffice of\b', # Matches "office of" (like "Office of the CEO")
r'\bassistant to\b', # Matches "assistant to" (like "Assistant to the CEO")
r'\bassistant\b', # Matches "assistant" in general
r'\bto the\b', # Matches "to the" (like "Assistant to the CEO")
r'\bof the\b', # Matches "of the"
r'\bfor the\b', # Matches "for the"
r'\bsecretary\b' # Matches "secretary"
]
# Define compound roles: these are complex executive roles that need special handling
# Format: (tuple_of_possible_ways_to_write_it, "STANDARDIZED_OUTPUT")
# Order matters: more specific roles should come before less specific ones
self.compound_role_definitions = [
# Chief Technology and Information Officer (handles both IT and tech)
(("chief technology and information officer", "chief information and technology officer", "chief technology & information officer", "chief information & technology officer", "ctio", "c.t.i.o"), "CTIO"),
# Chief Product and Technology Officer (handles both product and tech)
(("chief product and technology officer","chief technology and product officer", "ctpo", "cpto", "c.p.t.o"), "CPTO"),
# Chief Revenue Officer (handles sales, revenue, growth)
(("chief revenue officer", "chief sales officer", "chief commercial officer", "chief growth officer", "cro", "c.r.o"), "CRO"),
# Chief Human Resources Officer (handles people, talent, HR)
(("chief human resources officer", "chief people officer", "chief talent officer", "chief people and talent officer", "chief personnel officer", "chief human resource officer", "chief human capital officer"), "CHRO"),
(("assistant vice president",), "AVP")
]
# Define standard single roles
# Format: (tuple_of_possible_ways_to_write_it, "STANDARDIZED_OUTPUT")
self.role_definitions = [
# C-Suite Executive Roles (Chief level positions)
(("chief product officer", "cpo", "c.p.o"), "CPO"),
(("chief technology officer", "cto", "c.t.o"), "CTO"),
(("chief information officer", "cio", "c.i.o"), "CIO"),
(("chief executive officer", "ceo", "c.e.o"), "CEO"),
(("chief operating officer", "coo", "c.o.o"), "COO"),
(("chief financial officer", "chief finance officer", "cfo", "c.f.o"), "CFO"),
(("chief marketing officer", "cmo", "c.m.o"), "CMO"),
(("chief information security officer", "ciso", "c.i.s.o"), "CISO"),
# Board and Governance Roles
(("chairman",), "Chairman"), # Chairman of the board
(("board member", "board of directors", "board of trustees", "board advisor", "advisory board", "board"), "Board Member"),
# Senior Management Roles
(("partner",), "Partner"), # Like in consulting firms or law firms
(("general manager", "gm"), "General Manager"),
(("principal consultant",), "Principal Consultant"), # Senior consulting role
(("managing director",), "Managing Director"), # Common in international companies
(("executive director",), "Executive Director"),
(("senior director",), "Senior Director"), # Senior level director
(("director",), "Director"), # General director role
# Sales Roles
# Note: Senior Account Executive must come BEFORE Account Executive to avoid "senior account executive" matching just "account executive"
# Note: Abbreviations like "a.e" should NOT have trailing periods due to regex word boundary matching
(("senior account executive", "sr account executive", "sr. account executive",
"senior ae", "sr ae", "sr. ae", "senior a.e", "sr a.e", "sr. a.e"), "Senior Account Executive"),
(("account executive", "ae", "a.e", "account exec", "enterprise account executive",
"strategic account executive", "named account executive", "enterprise ae",
"strategic ae", "named ae"), "Account Executive"),
(("business development representative", "bdr", "b.d.r", "business development rep",
"bd rep", "business dev rep", "business dev representative"), "Business Development Representative"),
(("sales development representative", "sdr", "s.d.r", "sales development rep",
"sd rep", "sales dev rep", "sales dev representative"), "Sales Development Representative"),
]
# Special cases that need custom handling
self.special_case_role_definitions = [
(("chairman of the board",), "Board Member"), # This specific phrase maps to Board Member
]
def president_role_normalizer(self, title: str) -> Optional[str]:
"""
This method handles all variations of "President" and "Vice President" titles.
It returns the appropriate standardized form or None if no match is found.
The hierarchy is: SVP > EVP > VP > President
Args:
title: The job title text to analyze
Returns:
A standardized role string (like "SVP", "VP", "President") or None
"""
title_lower = title.lower()
# Check for Assistant Vice President first
if "assistant vice president" in title_lower:
return "AVP"
# Senior Vice President patterns - captures all variations of senior VP titles
svp_patterns = (
# Full written forms
"senior vice president", # Example: "Senior Vice President of Operations"
"sr vice president", # Example: "Sr Vice President, Finance"
"sr. vice president", # Example: "Sr. Vice President - Marketing"
# Abbreviated VP forms
"senior vp", # Example: "Senior VP of Sales"
"sr vp", # Example: "Sr VP, Technology"
"sr. vp", # Example: "Sr. VP - Human Resources"
# V.P variations with periods
"senior v.p", # Example: "Senior V.P of Business Development"
"sr v.p", # Example: "Sr V.P, Operations"
"sr. v.p", # Example: "Sr. V.P - Strategy"
# Vice Pres abbreviations
"senior vice pres", # Example: "Senior Vice Pres, Global Markets"
"sr vice pres", # Example: "Sr Vice Pres of Engineering"
"sr. vice pres", # Example: "Sr. Vice Pres - Product"
# Regex patterns for flexibility
r"^svp\b", # Example: "SVP Operations" (starts with SVP)
r"^s.v.p\b", # Example: "S.V.P Marketing" (starts with S.V.P)
r"\bsvp\b", # Example: "Global SVP" (SVP anywhere in title)
r"\bs\.v\.p\.?\b", # Example: "Regional S.V.P." (S.V.P with optional period)
# Comprehensive regex patterns
r"\bsenior\s+(?:vice\s+president|vp|v\.p\.?|vice\s+pres)\b", # Matches: "Senior Vice President", "Senior VP", "Senior V.P.", "Senior Vice Pres"
r"\bsr\.?\s+(?:vice\s+president|vp|v\.p\.?|vice\s+pres)\b", # Matches: "Sr Vice President", "Sr. VP", "Sr V.P", "Sr. Vice Pres"
)
# Executive Vice President patterns - captures all variations of executive VP titles
evp_patterns = (
# Full written forms
"executive vice president", # Example: "Executive Vice President of Technology"
"exec vice president", # Example: "Exec Vice President, Global Operations"
# Abbreviated VP forms
"executive vp", # Example: "Executive VP of Marketing"
"exec vp", # Example: "Exec VP, Sales & Distribution"
# V.P variations with periods
"executive v.p", # Example: "Executive V.P of Finance"
"exec v.p", # Example: "Exec V.P, Strategy"
# Vice Pres abbreviations
"executive vice pres", # Example: "Executive Vice Pres, International"
"exec vice pres", # Example: "Exec Vice Pres of Operations"
# Regex patterns for flexibility
r"^evp\b", # Example: "EVP Sales" (starts with EVP)
r"^e.v.p\b", # Example: "E.V.P Marketing" (starts with E.V.P)
r"\bevp\b", # Example: "Global EVP" (EVP anywhere in title)
r"\be\.v\.p\.?\b", # Example: "Regional E.V.P." (E.V.P with optional period)
# Comprehensive regex pattern
r"\b(?:executive|exec)\s+(?:vice\s+president|vp|v\.p\.?|vice\s+pres)\b", # Matches: "Executive Vice President", "Exec VP", "Executive V.P.", "Exec Vice Pres"
)
# Regional Vice President patterns - captures all variations of regional VP titles
rvp_patterns = (
# Full written forms
"regional vice president", # Example: "Regional Vice President, West Coast"
"reg vice president", # Example: "Reg Vice President of Sales"
# Abbreviated VP forms
"regional vp", # Example: "Regional VP, Northeast"
"reg vp", # Example: "Reg VP of Operations"
# V.P variations with periods
"regional v.p", # Example: "Regional V.P, Europe"
"reg v.p", # Example: "Reg V.P of Business Development"
# Vice Pres abbreviations
"regional vice pres", # Example: "Regional Vice Pres, Asia Pacific"
# Regex patterns for flexibility
r"\brvp\b", # Example: "RVP Sales", "Northeast RVP"
r"\brv\.p\.?\b", # Example: "RV.P Marketing", "RV.P."
r"\br\.v\.p\.?\b", # Example: "R.V.P Operations", "R.V.P."
# Comprehensive regex pattern
r"\b(?:regional|reg)\s+(?:vice\s+president|vp|v\.p\.?|vice\s+pres)\b", # Matches: "Regional Vice President", "Reg VP", "Regional V.P.", "Reg Vice Pres"
)
# Area/Assistant/Associate Vice President patterns - captures VP variations with qualifying prefixes
avp_patterns = (
# Area VP variations
"area vice president", # Example: "Area Vice President, Commercial Banking"
"area vp", # Example: "Area VP of Retail Operations"
"area v.p", # Example: "Area V.P, Southeast Region"
# Assistant VP variations
"assistant vice president", # Example: "Assistant Vice President, Risk Management"
"assistant vp", # Example: "Assistant VP of Finance"
"assistant v.p", # Example: "Assistant V.P, Operations"
# Associate VP variations
"associate vice president", # Example: "Associate Vice President, Investment Banking"
"associate vp", # Example: "Associate VP of Marketing"
"associate v.p", # Example: "Associate V.P, Technology"
# Regex patterns for flexibility
r"\bavp\b", # Example: "AVP Sales", "Commercial AVP"
r"\ba\.v\.p\.?\b", # Example: "A.V.P Marketing", "A.V.P."
# Comprehensive regex pattern
r"\b(?:area|assistant|associate)\s+(?:vice\s+president|vp|v\.p\.?|vice\s+pres)\b", # Matches: "Assistant Vice President", "Area VP", "Associate V.P.", etc.
)
# Standard Vice President patterns - captures basic VP titles without qualifiers
vp_patterns = (
# Full written forms
"vice president", # Example: "Vice President of Operations"
"vice pres", # Example: "Vice Pres, Global Sales"
# Abbreviated forms
"v president", # Example: "V President of Marketing"
"v pres", # Example: "V Pres, Technology"
# Regex patterns for flexibility
r"\bvp\b", # Example: "VP Sales", "Marketing VP"
r"\bv\.p\.?\b", # Example: "V.P Operations", "V.P."
# Comprehensive regex pattern
r"\bvice\s+(?:president|pres)\b", # Matches: "Vice President", "Vice Pres"
)
# President patterns - captures president titles (without "vice" qualifier)
president_patterns = (
# Regex patterns for flexibility
r"^president\b", # Example: "President" (starts with president)
r"\bpresident\b", # Example: "Regional President", "Division President"
r"^pres\b", # Example: "Pres" (starts with pres)
r"\bpres\b", # Example: "Regional Pres", "Division Pres"
# Combined President & CEO titles
"president & ceo", # Example: "President & CEO"
"president and ceo", # Example: "President and CEO"
"president/ceo", # Example: "President/CEO"
"pres & ceo", # Example: "Pres & CEO"
"pres and ceo", # Example: "Pres and CEO"
"pres/ceo", # Example: "Pres/CEO"
# Regex for combined titles
r"\bpresident\s*[&/]\s*ceo\b", # Matches: "President & CEO", "President/CEO", "President&CEO"
r"\bpres\s*[&/]\s*ceo\b", # Matches: "Pres & CEO", "Pres/CEO", "Pres&CEO"
)
# Check patterns in order of hierarchy
if any(re.search(pattern, title_lower) for pattern in svp_patterns):
return "SVP"
elif any(re.search(pattern, title_lower) for pattern in evp_patterns):
return "EVP"
elif any(re.search(pattern, title_lower) for pattern in rvp_patterns):
return "VP" # regional VP normalizes to VP
elif any(re.search(pattern, title_lower) for pattern in avp_patterns):
return "VP" # area VP normalizes to VP
elif any(re.search(pattern, title_lower) for pattern in vp_patterns):
return "VP"
elif any(re.search(pattern, title_lower) for pattern in president_patterns):
return "President"
return None
def director_role_normalizer(self, title: str) -> Optional[List[str]]:
"""
This method handles all variations of "Director" titles.
It returns the appropriate standardized form(s) or None if no match is found.
For titles with multiple qualifiers (e.g., "Executive Managing Director"),
it returns all applicable director roles.
Args:
title: The job title text to analyze
Returns:
A list of standardized role strings (like ["Executive Director", "Managing Director"]) or None
"""
title_lower = title.lower()
# Check if the title contains "director" or "dir" as a word
if not (re.search(r'\bdirector\b', title_lower) or re.search(r'\bdir\b', title_lower)):
return None
director_roles = []
# Executive Director patterns
executive_patterns = (
r"\bexecutive\s+(?:director|dir)\b",
r"\bexec\s+(?:director|dir)\b",
)
# Managing Director patterns
managing_patterns = (
r"\bmanaging\s+(?:director|dir)\b",
)
# Senior Director patterns
senior_patterns = (
r"\bsenior\s+(?:director|dir)\b",
r"\bsr\.?\s+(?:director|dir)\b",
r"\bsnr\.?\s+(?:director|dir)\b",
)
# Check for each pattern and collect all matches
# Also check for standalone qualifiers (e.g., "Executive Managing Director")
has_executive = re.search(r"\bexecutive\b", title_lower) or re.search(r"\bexec\b", title_lower)
has_managing = re.search(r"\bmanaging\b", title_lower)
has_senior = re.search(r"\bsenior\b", title_lower) or re.search(r"\bsr\.?\b", title_lower) or re.search(r"\bsnr\.?\b", title_lower)
# Add roles based on what qualifiers are present
if has_executive:
director_roles.append("Executive Director")
if has_managing:
director_roles.append("Managing Director")
if has_senior:
director_roles.append("Senior Director")
# If no specific qualifiers found but contains "director", add generic Director
if not director_roles and (re.search(r'\bdirector\b', title_lower) or re.search(r'\bdir\b', title_lower)):
director_roles.append("Director")
return director_roles if director_roles else None
def clevel_catch_all_normalizer(self, title: str) -> Optional[str]:
"""
Catches C-level roles that don't match existing definitions.
Matches patterns like "Chief X Officer" and returns "C Level".
"""
title_lower = title.lower()
# List of already-handled C-level abbreviations
known_clevel = {'ceo', 'cto', 'cio', 'cfo', 'coo', 'cmo', 'ciso', 'cpo',
'chro', 'cro', 'ctio', 'cpto'}
# Check if this is a known C-level abbreviation (already handled)
for abbrev in known_clevel:
if re.search(r'\b' + abbrev + r'\b', title_lower):
return None
# Match "Chief X Officer" pattern for unknown C-level roles
if re.search(r'\bchief\b.*\bofficer\b', title_lower):
return "C Level"
return None
def _is_support_or_lower_rank_role(self, lower_title: str) -> bool:
"""
This method checks if a job title contains words that indicate it's a support role
or lower-level position that we want to filter out.
Args:
lower_title: The job title in lowercase
Returns:
True if this is a support/lower role (should be filtered out)
False if this might be a senior role (should be kept)
"""
# Allow any role in the exception allow-list, even if it contains blocked phrases
for exc in ALLOWED_ROLE_EXCEPTIONS:
if exc in lower_title:
return False # Do not filter out exceptions
# Loop through each exclusion pattern we defined earlier
for pattern in self.exclusion_patterns:
# If we find any exclusionary word in the title, reject it
if re.search(pattern, lower_title):
return True
# If no exclusionary words found, this might be a valid senior role
return False
def add_role_group(self, normalized_roles: List[str], trigger_roles: List[str], group_role: str) -> None:
"""
Adds a group role to the normalized roles list if any of the trigger roles are present.
This allows for easy extension of role groupings.
Args:
normalized_roles: The list of normalized roles to potentially add to
trigger_roles: List of roles that, if present, will trigger adding the group role
group_role: The group role to add if any trigger role is found
"""
if normalized_roles and any(role in trigger_roles for role in normalized_roles):
if group_role not in normalized_roles:
normalized_roles.append(group_role)
def normalize_employee_title(self, raw_title: Optional[str]) -> Optional[List[str]]:
"""
This is the main method that takes a raw job title and converts it to standardized form(s).
For example:
- "Chief Executive Officer" → ["CEO"]
- "CEO and CTO" → ["CEO", "CTO"]
- "Assistant to the CEO" → None (filtered out)
- "VP of Sales and Marketing" → ["VP"]
Args:
raw_title: The original job title as a string (can be None/empty)
Returns:
A list of standardized role names, or None if the title should be filtered out
"""
# If no title provided, return None
if not raw_title:
return None
# Clean up the title: make lowercase and remove extra spaces
processed_lower_title = raw_title.lower().strip()
# Replace multiple spaces with single space (regex: \s+ means one or more whitespace)
processed_lower_title = re.sub(r'\s+', ' ', processed_lower_title)
# If title is empty after cleaning, return None
if not processed_lower_title:
return None
# Exception routine!
for allow_phrase, norm in ALLOWED_ROLE_EXCEPTIONS.items():
if allow_phrase in processed_lower_title:
return [norm]
# Keep track of the remaining title text as we process it
remaining_title = processed_lower_title
# Store the standardized roles we find
normalizedRoles = []
# STEP 1: Check for special cases first (like "chairman of the board")
for keywords, normalized_form in self.special_case_role_definitions:
for keyword in keywords:
if keyword in remaining_title:
normalizedRoles.append(normalized_form)
# Remove this phrase from remaining title so we don't double-process it
remaining_title = remaining_title.replace(keyword, "")
break # Stop looking once we find a match
# STEP 2: Check if this is a support role that should be filtered out
# But only filter if we haven't found any valid roles yet
if self._is_support_or_lower_rank_role(processed_lower_title) and not normalizedRoles:
return None
if re.search(r'\bchro\b', processed_lower_title) and not re.search(r'\bco\b', processed_lower_title):
normalizedRoles.append("CHRO")
remaining_title = re.sub(r'\bchro\b', '', remaining_title)
# STEP 3: Look for compound roles (like "Chief Technology and Information Officer")
for keywords, normalized_form in self.compound_role_definitions:
for keyword in keywords:
if keyword in remaining_title:
normalizedRoles.append(normalized_form)
# Remove this phrase so we don't process it again
remaining_title = remaining_title.replace(keyword, "")
break # Stop looking once we find a match
# STEP 4: Split the remaining title into individual roles
# Split on common separators: / & | ? , - ; and the word "and"
# Also split on multiple consecutive periods (2+) but not single periods (preserves C.E.O)
rolesInTitle = re.split(r'[/&|?,\-;]|\.{2,}|\band\b', remaining_title)
# STEP 5: Process each individual role
for role in rolesInTitle:
role = role.strip() # Remove spaces from beginning and end
if not role: # Skip empty strings
continue
if "assistant vice president" in role.lower():
normalizedRoles.append("AVP")
continue
# Remove punctuation for cleaner matching
role_for_matching = re.sub(r'[^\w\s]', '', role.lower())
# STEP 5a: Check if this role contains president/VP keywords
if ('president' in role or
role_for_matching in {'svp', 'evp', 'vp', 'avp', 'rvp', 'svp', 'evp', 'vp', 'avp', 'rvp'} or
role.lower().startswith('svp') or
role.lower().startswith('evp') or
role.lower().startswith('vp') or
role.lower().startswith('avp') or
role.lower().startswith('rvp')):
# Use our special president normalizer for these
presidentNormalizedRole = self.president_role_normalizer(role)
if presidentNormalizedRole:
normalizedRoles.append(presidentNormalizedRole)
continue # Move to next role
# STEP 5b: Check if this role contains director keywords
if 'director' in role.lower() or re.search(r'\bdir\b', role.lower()):
# Use our special director normalizer for these
directorNormalizedRoles = self.director_role_normalizer(role)
if directorNormalizedRoles:
normalizedRoles.extend(directorNormalizedRoles)
continue # Move to next role
# STEP 5c: Check against our standard role definitions
matched_in_5c = False
for keywords, normalized_form in self.role_definitions:
for keyword in keywords:
# Create a pattern that matches the keyword as a whole word
pattern = r'\b' + re.escape(keyword) + r'\b'
if re.search(pattern, role):
normalizedRoles.append(normalized_form)
matched_in_5c = True
break # Stop looking for this role once we find a match
else:
continue # Continue to next keyword if no match found
break # Break out of outer loop too once we find a match
# STEP 5d: Check for unknown C-level roles (only if no match in 5c)
if not matched_in_5c:
clevel_result = self.clevel_catch_all_normalizer(role)
if clevel_result:
normalizedRoles.append(clevel_result)
continue
# Add role groups - makes it easy to tag people with multiple related roles
self.add_role_group(normalizedRoles, ["CTO", "CIO", "CPO", "CTIO", "CPTO"], "CITPO")
# Return the list of normalized roles, or None if we didn't find any
return normalizedRoles if normalizedRoles else None
# This section only runs when the file is executed directly (not imported)
if __name__ == '__main__':
"""
This is a comprehensive test suite that validates the role normalizer works correctly.
It tests hundreds of different job title variations to ensure they're processed properly.
"""
# Create an instance of our RoleNormalizer class
normalizer = RoleNormalizer()
# Dictionary of test cases: {input_title: expected_output}
test_titles = {
# === BASIC SINGLE ROLES ===
# Testing that standard C-suite titles are recognized correctly
"Chief Product Officer": ["CPO", 'CITPO'],
"Chief Technology Officer": ["CTO", 'CITPO'],
"Chief Information Officer": ["CIO", 'CITPO'],
"Chief Executive Officer": ["CEO"],
"Chief Operating Officer": ["COO"],
"Chief Financial Officer": ["CFO"],
"Chief Finance Officer": ["CFO"], # Alternative phrasing
"Chief Marketing Officer": ["CMO"],
"Chief Information Security Officer": ["CISO"],
# Testing board and governance roles
"Board Member": ["Board Member"],
"Board of Directors": ["Board Member"],
"Board of Trustees": ["Board Member"],
"Board Advisor": ["Board Member"],
"Advisory Board": ["Board Member"],
"Board": ["Board Member"],
"Chairman": ["Chairman"],
# Testing senior management roles
"Partner": ["Partner"],
"General Manager": ["General Manager"],
"GM": ["General Manager"], # Abbreviation
"Principal Consultant": ["Principal Consultant"],
"Managing Director": ["Managing Director"],
"Executive Director": ["Executive Director"],
"Senior Director": ["Senior Director"],
"Director": ["Director"],
# === COMPOUND ROLES ===
# Testing complex executive roles that combine multiple functions
"Chief Technology and Information Officer": ["CTIO", 'CITPO'],
"Chief Information and Technology Officer": ["CTIO", 'CITPO'],
"Chief Product and Technology Officer": ["CPTO", 'CITPO'],
"Chief Technology and Product Officer": ["CPTO", 'CITPO'],
"Chief Revenue Officer": ["CRO"],
"Chief Sales Officer": ["CRO"],
"Chief Commercial Officer": ["CRO"],
"Chief Growth Officer": ["CRO"],
"Chief Human Resources Officer": ["CHRO"],
"Chief People Officer": ["CHRO"],
"Chief Talent Officer": ["CHRO"],
"Chief People and Talent Officer": ["CHRO"],
"Chief Personnel Officer": ["CHRO"],
"Chief Human Resource Officer": ["CHRO"],
"Chief Human Capital Officer": ["CHRO"],
# === PRESIDENT VARIATIONS ===
# Testing the hierarchy of president roles
"Senior Vice President": ["SVP"],
"Sr Vice President": ["SVP"],
"Sr. Vice President": ["SVP"],
"SVP": ["SVP"],
"Executive Vice President": ["EVP"],
"Exec Vice President": ["EVP"],
"EVP": ["EVP"],
"Regional Vice President": ["VP"],
"RVP": ["VP"],
"Area Vice President": ["VP"],
"AVP": ["VP"],
"Vice President": ["VP"],
"VP": ["VP"],
"President": ["President"],
# === DIRECTOR VARIATIONS ===
# Testing the hierarchy of director roles
"Executive Director": ["Executive Director"],
"Exec Director": ["Executive Director"],
"Executive Dir": ["Executive Director"],
"Exec Dir": ["Executive Director"],
"Managing Director": ["Managing Director"],
"Managing Dir": ["Managing Director"],
"Senior Director": ["Senior Director"],
"Senior Dir": ["Senior Director"],
"Sr Director": ["Senior Director"],
"Sr Dir": ["Senior Director"],
"Sr. Director": ["Senior Director"],
"Sr. Dir": ["Senior Director"],
"Snr Director": ["Senior Director"],
"Snr Dir": ["Senior Director"],
"Snr. Director": ["Senior Director"],
"Snr. Dir": ["Senior Director"],
"Director": ["Director"],
"Dir": ["Director"],
# === CASING VARIATIONS ===
# Testing that different capitalization works
"CEO": ["CEO"],
"ceo": ["CEO"],
"Chief Executive Officer": ["CEO"],
"chief executive officer": ["CEO"],
"CHIEF EXECUTIVE OFFICER": ["CEO"],
"ChIeF eXeCuTiVe OfFiCeR": ["CEO"],
# === SPACING VARIATIONS ===
# Testing that extra spaces are handled correctly
" CEO": ["CEO"],
"CEO ": ["CEO"],
" CEO ": ["CEO"],
" Chief Executive Officer ": ["CEO"],
"Chief Executive Officer": ["CEO"], # Multiple spaces between words
# === MULTIPLE ROLES WITH DIFFERENT SEPARATORS ===
# Testing titles that contain multiple roles separated by various symbols
"President and CEO": ["President", "CEO"],
"CTO and CEO": ["CTO", "CEO", "CITPO"],
"CTO/CEO": ["CTO", "CEO", "CITPO"],
"CTO / CEO": ["CTO", "CEO", "CITPO"],
"CTO/ CEO": ["CTO", "CEO", "CITPO"],
"CTO&CEO": ["CTO", "CEO", "CITPO"],
"CTO|CEO": ["CTO", "CEO", "CITPO"],
"CTO?CEO": ["CTO", "CEO", "CITPO"],
"CTO-CEO": ["CTO", "CEO", "CITPO"],
"CTO,CEO": ["CTO", "CEO", "CITPO"],
"CEO & CTO": ["CEO", "CTO", "CITPO"],
"CEO, CTO, COO": ["CEO", "CTO", "COO", "CITPO"],
"CEO/CTO/COO": ["CEO", "CTO", "COO", "CITPO"],
"CEO & CTO & COO": ["CEO", "CTO", "COO", "CITPO"],
"CEO|CTO|COO": ["CEO", "CTO", "COO", "CITPO"],
# === COMPLEX COMPOUND ROLE COMBINATIONS ===
# Testing compound roles combined with other roles
"SVP and Chief Information and Technology Officer": ["CTIO", "SVP", "CITPO"],
"Executive Vice President and Chief Product and Technology Officer": ["CPTO", "EVP", "CITPO"],
"VP and Chief Technology and Information Officer": ["CTIO", "VP", 'CITPO'],
"President and Chief Technology and Product Officer": ["CPTO", "President", 'CITPO'],
# === ROLES WITH CONTEXT/QUALIFIERS ===
# Testing titles with additional context that should be ignored
"Facebook CEO": ["CEO"],
"CEO of Facebook": ["CEO"],
"CEO at Google": ["CEO"],
"Google CEO": ["CEO"],
"Former CEO": ["CEO"],
"Interim CEO": ["CEO"],
"Acting CEO": ["CEO"],
"Co-CEO": ["CEO"],
"Founder and CEO": ["CEO"],
"Founder & CEO": ["CEO"],
"CEO and Founder": ["CEO"],
"Owner and CEO": ["CEO"],
"Founder/CEO": ["CEO"],
# === VALID COMPLEX CASES ===
# Testing roles with additional descriptors
"Senior Vice President of Engineering": ["SVP"],
"Vice President of Sales": ["VP"],
"EVP of Marketing": ["EVP"],
"Chief Technology Officer and Co-Founder": ["CTO", 'CITPO'],
"Board Member and Advisor": ["Board Member"],
"Managing Director, Europe": ["Managing Director"],
"General Manager - North America": ["General Manager"],
"Principal Consultant, Strategy": ["Principal Consultant"],
# === EXCLUSION CASES (should return None) ===
# Testing titles that should be filtered out as support/junior roles
"Assistant to the CEO": None,
"Personal Assistant to the CEO": None,
"Executive Assistant": None,
"Assistant": None,
"Junior Developer": None,
"Senior Consultant": None, # Contains "consultant" but not "principal consultant"
"Marketing Consultant": None,
"IT Consultant": None,
"Consultant": None,
"Intern": None,
"Trainee": None,
"Deputy CEO": None,
"Associate Director": None,
"Coordinator": None,
"Secretary": None,
"Personal Assistant": None,
"PA": None,
"Assistant Vice President": None,
"Office of the CEO": None,
"To the CEO": None,
"For the CEO": None,
"Of the CEO": None,
# === DIRECTOR WITH CONTEXT/QUALIFIERS ===
# Testing director titles with additional context
"Director of Engineering": ["Director"],
"Director of Sales": ["Director"],
"Senior Director of Operations": ["Senior Director"],
"Executive Director of Marketing": ["Executive Director"],
"Managing Director Europe": ["Managing Director"],
"Regional Director": ["Director"],
"Technical Director": ["Director"],
"Finance Director": ["Director"],
"Operations Director": ["Director"],
"IT Director": ["Director"],
"Marketing Director": ["Director"],
"Sales Director": ["Director"],
"Product Director": ["Director"],
"Engineering Director": ["Director"],
# === DIRECTOR COMBINATIONS WITH OTHER ROLES ===
# Testing director titles combined with other roles
"Director and VP": ["Director", "VP"],
"CEO and Director": ["CEO", "Director"],
"Senior Director and Board Member": ["Senior Director", "Board Member"],
"Managing Director and CEO": ["Managing Director", "CEO"],
"Executive Director and CTO": ["Executive Director", "CTO", "CITPO"],
"Director & Partner": ["Director", "Partner"],
# === DIRECTOR CASING VARIATIONS ===
# Testing different capitalization for directors
"director": ["Director"],
"DIRECTOR": ["Director"],
"Director": ["Director"],
"senior director": ["Senior Director"],
"SENIOR DIRECTOR": ["Senior Director"],
"Senior Director": ["Senior Director"],
"managing director": ["Managing Director"],
"MANAGING DIRECTOR": ["Managing Director"],
"executive director": ["Executive Director"],
"EXECUTIVE DIRECTOR": ["Executive Director"],
# === DIRECTOR ABBREVIATION VARIATIONS ===
# Testing abbreviated director forms
"Sr. Dir. of Engineering": ["Senior Director"],
"Exec Dir of Sales": ["Executive Director"],
"Snr. Dir. Marketing": ["Senior Director"],
"Dir of Product": ["Director"],
"Dir.": ["Director"],
# === DIRECTOR WITH MULTIPLE SEPARATORS ===
# Testing director titles with various separators
"Director/VP": ["Director", "VP"],
"Director & CEO": ["Director", "CEO"],
"Senior Director/Executive Director": ["Senior Director", "Executive Director"],
"Managing Director, Board Member": ["Managing Director", "Board Member"],
"Director | CTO": ["Director", "CTO", "CITPO"],
# === EDGE CASES AND MALFORMED INPUTS ===
# Testing unusual inputs and edge cases
"": None,
" ": None,
"CEO?": ["CEO"],
"CEO!": ["CEO"],
"CEO.": ["CEO"],
"CEO;": ["CEO"],
"CEO:": ["CEO"],
"CEO@Company": ["CEO"],
"CEO#1": ["CEO"],
"CEO123": None, # Number attached - not a clean role
"123CEO": None, # Number prefix - not a clean role
# === MIXED VALID/INVALID COMBINATIONS ===
# Testing titles that mix valid roles with terms that should be ignored
"Consultant and CEO": ["CEO"], # Should extract CEO, ignore consultant
"CEO and Assistant": None, # Should extract CEO, ignore assistant
"Intern and Board Member": None, # Should extract Board Member, ignore intern
# === TRICKY EXCLUSION CASES ===
# Testing that our word boundary matching works correctly
"AVPian": None, # Contains "avp" but not as standalone word
"CEOLia": None, # Contains "ceo" but not as standalone word
"VPerson": None, # Contains "vp" but not as standalone word
"Consultant CEO": ["CEO"], # Should extract CEO despite consultant
"CEO Consultant": ["CEO"], # Should extract CEO despite consultant
# === ABBREVIATION EDGE CASES ===
# Testing abbreviations with periods
"C.E.O": ["CEO"], # With periods
"C.T.O": ["CTO", 'CITPO'],
"C.F.O": ["CFO"],
"S.V.P": ["SVP"],
"V.P.": ["VP"],
# === LONG COMPLEX TITLES ===
# Testing very complex titles with multiple roles
"Senior Vice President of Engineering and Chief Technology Officer": ["SVP", "CTO", 'CITPO'],
"Executive Vice President, Chief Information Officer and Board Member": ["EVP", "CIO", "Board Member", 'CITPO'],
"Founder, CEO and Chairman of the Board": ["Board Member", "CEO"],
# === TYPOS AND VARIATIONS ===
# Testing common misspellings
"Cheif Executive Officer": None, # "Cheif" typo - doesn't match "chief" pattern
"Chief Excecutive Officer": ["C Level"], # Caught by C-level catch-all (has "chief" and "officer")
"Chief Executive Oficer": None, # "Oficer" typo - doesn't match "officer" pattern
# === INTERNATIONAL VARIATIONS ===
# Testing international business titles
"Managing Director": ["Managing Director"],
"Executive Director": ["Executive Director"],
"Director General": ["Director"], # Not in our definitions
"Group CEO": ["CEO"],
"Regional CEO": ["CEO"],
"Division CEO": ["CEO"],
# === NUMERIC AND SPECIAL CHARACTER EDGE CASES ===
# Testing titles with numbers and special characters
"CEO 2024": ["CEO"],
"CEO (Acting)": ["CEO"],
"CEO [Interim]": ["CEO"],
"CEO - Technology": ["CEO"],
"CEO/President": ["CEO", "President"],
"CEO & President": ["CEO", "President"],
# === BOUNDARY TESTING ===
# Testing very short inputs
"C": None, # Single character
"CE": None, # Two characters
"CEOO": None, # Close to CEO but not exact
"PRESIDENT": ["President"], # All caps
"president": ["President"], # All lowercase
# === MULTIPLE COMPOUND ROLES ===
# Testing multiple compound roles in one title
"Chief Technology and Information Officer and Chief Product and Technology Officer": ["CTIO", "CPTO", 'CITPO'],
"CTIO and CPTO": ["CTIO", "CPTO", 'CITPO'],
# === ROLES WITH MULTIPLE EXCLUSION WORDS ===
# Testing titles with multiple exclusionary terms
"Junior Assistant Consultant": None, # Multiple exclusion words
"Deputy Assistant to the CEO": None, # Multiple exclusion words
"Assistant Deputy Coordinator": None, # Multiple exclusion words
# === WHITESPACE AND UNICODE EDGE CASES ===
# Testing various whitespace characters
"\tCEO\t": ["CEO"], # Tabs
"\nCEO\n": ["CEO"], # Newlines
"CEO\r": ["CEO"], # Carriage return
# === COMPOUND ROLE STRESS TESTS ===
# Testing very complex combinations
"SVP and Chief Information and Technology Officer and Board Member": ["CTIO", "SVP", "Board Member", 'CITPO'],
"President and Chief Technology and Product Officer and Chairman": ["CPTO", "President", "Chairman", 'CITPO'],
# === TRICKY ABBREVIATION COMBINATIONS ===
# Testing that abbreviations are properly distinguished
"CTIO": ["CTIO", 'CITPO'], # Standalone CTIO
"C.T.I.O": ["CTIO", 'CITPO'], # CTIO with periods
"CPTO": ["CPTO", 'CITPO'], # Standalone CPTO
"C.P.T.O": ["CPTO", 'CITPO'], # CPTO with periods
"CRO": ["CRO"], # Standalone CRO
"C.R.O": ["CRO"], # CRO with periods
"CTIO/CPTO": ["CTIO", "CPTO", 'CITPO'], # Slash separator
"CTIO & CPTO": ["CTIO", "CPTO", 'CITPO'], # Ampersand separator
"CTIO, CPTO, CRO": ["CTIO", "CPTO", "CRO", 'CITPO'], # Multiple compound roles
"CTO and CTIO": ["CTIO","CTO", 'CITPO'], # Mix of standard and compound
"CEO and CRO": ["CRO","CEO"], # CEO with compound role
# === TRICKY VP VARIATIONS ===
# Testing complex VP title patterns
"SVP and EVP": ["SVP", "EVP"], # Multiple VP levels
"SVP, EVP, VP": ["SVP", "EVP", "VP"], # All VP levels
"Senior Vice President and Executive Vice President": ["SVP", "EVP"],
"S.V.P and E.V.P": ["SVP", "EVP"], # Abbreviated forms
"Vice President & Senior Vice President": ["VP", "SVP"],
"AVP of Sales": ["VP"], # Assistant VP (should normalize to AVP not VP based on line 109-110)
"Assistant Vice President of Marketing": None,
"RVP and SVP": ["VP", "SVP"], # Regional VP normalizes to VP
"Regional Vice President and Senior Vice President": ["VP", "SVP"],
# === MIXED CASE ABBREVIATIONS ===
# Testing case sensitivity handling
"ceo": ["CEO"], # All lowercase
"cEo": ["CEO"], # Mixed case
"CeO": ["CEO"], # Mixed case
"cto and cfo": ["CTO", "CFO", 'CITPO'], # Multiple lowercase
"Cto And Cfo": ["CTO", "CFO", 'CITPO'], # Title case
"svp": ["SVP"], # Lowercase SVP
"Svp": ["SVP"], # Title case SVP
"ctio and cpto": ["CTIO", "CPTO", 'CITPO'], # Lowercase compound roles
"Ctio And Cpto": ["CTIO", "CPTO", 'CITPO'], # Title case compound roles
# === TRICKY WORD BOUNDARY CASES ===
# Testing that partial matches don't cause false positives
"President of Technology": ["President"], # "of" shouldn't break it
"Vice President for Operations": ["VP"], # "for" in title
"SVP - Global Sales": ["SVP"], # Hyphen with context
"Chief Executive Officer (CEO)": ["CEO"], # Parenthetical abbreviation
"CEO [Retired]": ["CEO"], # Brackets in title
"Ex-CEO": ["CEO"], # Prefix with hyphen
"Co-President": ["President"], # Co- prefix
"Co-CEO and Co-CTO": ["CEO", "CTO", 'CITPO'], # Multiple co- prefixes
# === EXCLUSION WORD COMBINATIONS ===
# Testing that exclusion words properly filter but with exceptions
"VP and Assistant": None, # VP mixed with exclusion word - should filter
"Assistant and VP": None, # Exclusion word first
"Coordinator and CEO": None, # Exclusion word with valid role
"CEO and Coordinator": None, # Valid role first
"Intern and Board Member": None, # Exclusion word with valid role
"Deputy to the CEO": None, # Multiple exclusion patterns
"Associate to the President": None, # Multiple exclusion patterns
# === COMPOUND ROLE WITH QUALIFIERS ===
# Testing compound roles with additional context
"Chief Revenue Officer and Board Member": ["CRO", "Board Member"],
"CRO & CEO": ["CRO", "CEO"],
"CHRO and CFO": ["CHRO", "CFO"],
"Chief Human Resources Officer and Chief Financial Officer": ["CHRO", "CFO"],
"Former CTIO": ["CTIO", 'CITPO'], # Qualifier before compound role
"Interim CRO": ["CRO"], # Qualifier before compound role
"Acting CPTO": ["CPTO", 'CITPO'], # Qualifier before compound role
# === PUNCTUATION EDGE CASES ===
# Testing unusual punctuation combinations
"CEO / CTO / CFO": ["CEO", "CTO", "CFO", 'CITPO'], # Spaces around slashes
"CEO| CTO |CFO": ["CEO", "CTO", "CFO", 'CITPO'], # Pipes with varied spacing
"CEO;CTO;CFO": ["CEO", "CTO", "CFO", 'CITPO'], # Semicolons
"CEO...CTO": ["CEO", "CTO", 'CITPO'], # Multiple dots (should split on standard separators)
"CEO--CTO": ["CEO", "CTO", 'CITPO'], # Double hyphen
"CEO & CTO & CFO & COO": ["CEO", "CTO", "CFO", "COO", 'CITPO'], # Multiple ampersands
# === ROLE WITH NUMBERS AND SPECIAL CHARS ===
# Testing roles with extraneous characters
"CEO #1": ["CEO"], # Hash with number
"VP (2024)": ["VP"], # Year in parentheses
"CTO v2.0": ["CTO", 'CITPO'], # Version number
"CEO*": ["CEO"], # Asterisk
"~CEO~": ["CEO"], # Tildes
"CEO+": ["CEO"], # Plus sign
"CEO=": ["CEO"], # Equals sign
# === PRESIDENT COMBINATIONS ===
# Testing complex president title combinations
"President & CEO & Chairman": ["President", "CEO", "Chairman"],
"President and CTO": ["President", "CTO", 'CITPO'],
"SVP and President": ["SVP", "President"],
"President/SVP": ["President", "SVP"],
"President & SVP & EVP": ["President", "SVP", "EVP"],
# === BOARD VARIATIONS ===
# Testing different board title formats
"Board Member and CEO": ["Board Member", "CEO"],
"Board of Directors and CTO": ["Board Member", "CTO", 'CITPO'],
"Chairman and CEO": ["Chairman", "CEO"],
"Chairman of the Board": ["Board Member"], # Special case mapping
"Chairman & President": ["Chairman", "President"],
"Advisory Board and Managing Director": ["Board Member", "Managing Director"],
# === AMBIGUOUS SEPARATORS ===
# Testing titles where separators might be ambiguous
"CEO-Founder": ["CEO"], # Hyphen might be part of compound title
"Founder-CEO": ["CEO"], # Reverse order
"CEO-President": ["CEO", "President"], # Two roles with hyphen
"CTO-VP": ["CTO", "VP", 'CITPO'], # Abbreviated roles with hyphen
# === REALLY LONG COMPLEX TITLES ===
# Testing extremely complex multi-role titles
"CEO, CTO, CFO, COO, CMO": ["CEO", "CTO", "CFO", "COO", "CMO", 'CITPO'],
"SVP and EVP and VP and President": ["SVP", "EVP", "VP", "President"],
"CTIO, CPTO, CRO, CHRO": ["CHRO", "CTIO", "CPTO", "CRO", 'CITPO'],
"Chief Executive Officer and Chief Technology Officer and Chief Financial Officer": ["CEO", "CTO", "CFO", 'CITPO'],
"Board Member, CEO, President, Chairman": ["Board Member", "CEO", "President", "Chairman"],
# === PARTIAL ROLE NAMES ===
# Testing that partial matches don't incorrectly match
"Chief": None, # Just "Chief" without a role
"Officer": None, # Just "Officer"
"Vice": None, # Just "Vice"
"President of": ["President"], # Incomplete title
"Senior Vice": None, # Incomplete VP title
# === CONFUSING SIMILAR TITLES ===
# Testing titles that might be confused with each other
"COO and CTO": ["COO", "CTO", 'CITPO'], # Similar looking abbreviations
"CIO and CEO": ["CIO", "CEO", 'CITPO'], # Similar sounding roles
"CMO and CTO": ["CMO", "CTO", 'CITPO'], # Different roles
"CISO and CIO": ["CISO", "CIO", 'CITPO'], # Security vs Information
# === INTERNATIONAL TITLE VARIATIONS ===
# Testing international equivalents
"Managing Director and CEO": ["Managing Director", "CEO"],
"Executive Director and Managing Director": ["Executive Director", "Managing Director"],
"Managing Director & Board Member": ["Managing Director", "Board Member"],
"General Manager and CEO": ["General Manager", "CEO"],
"Senior Director EMEA": ["Senior Director"],
"Director Asia Pacific": ["Director"],
"Regional Managing Director": ["Managing Director"],
"Group Director": ["Director"],
# === SPECIAL CHARACTERS IN CONTEXT ===
# Testing roles with special characters nearby
"«CEO»": ["CEO"], # Guillemets
"‹CTO›": ["CTO", 'CITPO'], # Single guillemets
"【CFO】": ["CFO"], # CJK brackets
"[CEO]": ["CEO"], # Square brackets
"{CTO}": ["CTO", 'CITPO'], # Curly braces
"<CFO>": ["CFO"], # Angle brackets
# === EDGE CASES WITH 'AND' ===
# Testing that 'and' is properly handled as separator
"Chief Technology and Information Officer": ["CTIO", 'CITPO'], # 'and' as part of role name
"CTO and CEO": ["CTO", "CEO", "CITPO"], # 'and' as separator
"Chief Product and Technology Officer": ["CPTO", 'CITPO'], # 'and' as part of role name
"CPO and CTO": ["CPO", "CTO", 'CITPO'], # 'and' as separator
"Chief People and Talent Officer": ["CHRO"], # 'and' as part of role name
"CHRO and CEO": ["CHRO", "CEO"], # 'and' as separator
# === DIRECTOR EDGE CASES ===
# Testing unusual director title patterns
"Dir of IT": ["Director"],
"Sr. Dir": ["Senior Director"],
"Snr Dir.": ["Senior Director"],
"Executive Director (Acting)": ["Executive Director"],
"Interim Managing Director": ["Managing Director"],
"Former Senior Director": ["Senior Director"],
"Co-Director": ["Director"],
"Director-at-Large": ["Director"],
"Director Emeritus": ["Director"],
"Senior Director, Global Operations": ["Senior Director"],
"Executive Director & CEO": ["Executive Director", "CEO"],
"Managing Director / President": ["Managing Director", "President"],
"Director of Directors": ["Director"], # Unusual but should work
"Executive Managing Director": ["Executive Director", "Managing Director"], # Both qualifiers
"Senior Executive Director": ["Executive Director", "Senior Director"], # Both qualifiers
"Managing Senior Director": ["Managing Director", "Senior Director"], # Both qualifiers
"Executive Managing Senior Director": ["Executive Director", "Managing Director", "Senior Director"], # All three qualifiers
# === ACCOUNT EXECUTIVE ROLES ===
# Basic Account Executive variations
"Account Executive": ["Account Executive"],
"account executive": ["Account Executive"],
"ACCOUNT EXECUTIVE": ["Account Executive"],
"AE": ["Account Executive"],
"ae": ["Account Executive"],
"A.E.": ["Account Executive"],
"a.e.": ["Account Executive"],
"Account Exec": ["Account Executive"],
"account exec": ["Account Executive"],
# Enterprise/Strategic/Named AE (should normalize to Account Executive)
"Enterprise Account Executive": ["Account Executive"],
"enterprise account executive": ["Account Executive"],
"Strategic Account Executive": ["Account Executive"],
"Named Account Executive": ["Account Executive"],
"Enterprise AE": ["Account Executive"],
"Strategic AE": ["Account Executive"],
"Named AE": ["Account Executive"],
# === SENIOR ACCOUNT EXECUTIVE ROLES ===
"Senior Account Executive": ["Senior Account Executive"],
"senior account executive": ["Senior Account Executive"],
"SENIOR ACCOUNT EXECUTIVE": ["Senior Account Executive"],
"Sr Account Executive": ["Senior Account Executive"],
"Sr. Account Executive": ["Senior Account Executive"],
"sr account executive": ["Senior Account Executive"],
"sr. account executive": ["Senior Account Executive"],
"Senior AE": ["Senior Account Executive"],
"senior ae": ["Senior Account Executive"],
"Sr AE": ["Senior Account Executive"],
"Sr. AE": ["Senior Account Executive"],
"sr ae": ["Senior Account Executive"],
"sr. ae": ["Senior Account Executive"],
"Senior A.E.": ["Senior Account Executive"],
"Sr A.E.": ["Senior Account Executive"],
"Sr. A.E.": ["Senior Account Executive"],
# === BUSINESS DEVELOPMENT REPRESENTATIVE ROLES ===
"Business Development Representative": ["Business Development Representative"],
"business development representative": ["Business Development Representative"],
"BUSINESS DEVELOPMENT REPRESENTATIVE": ["Business Development Representative"],
"BDR": ["Business Development Representative"],
"bdr": ["Business Development Representative"],
"B.D.R.": ["Business Development Representative"],
"b.d.r.": ["Business Development Representative"],
"Business Development Rep": ["Business Development Representative"],
"business development rep": ["Business Development Representative"],
"BD Rep": ["Business Development Representative"],
"bd rep": ["Business Development Representative"],
"Business Dev Rep": ["Business Development Representative"],
"business dev rep": ["Business Development Representative"],
"Business Dev Representative": ["Business Development Representative"],
# === SALES DEVELOPMENT REPRESENTATIVE ROLES ===
"Sales Development Representative": ["Sales Development Representative"],
"sales development representative": ["Sales Development Representative"],
"SALES DEVELOPMENT REPRESENTATIVE": ["Sales Development Representative"],
"SDR": ["Sales Development Representative"],
"sdr": ["Sales Development Representative"],
"S.D.R.": ["Sales Development Representative"],
"s.d.r.": ["Sales Development Representative"],
"Sales Development Rep": ["Sales Development Representative"],
"sales development rep": ["Sales Development Representative"],
"SD Rep": ["Sales Development Representative"],
"sd rep": ["Sales Development Representative"],
"Sales Dev Rep": ["Sales Development Representative"],
"sales dev rep": ["Sales Development Representative"],
"Sales Dev Representative": ["Sales Development Representative"],
# === SALES ROLES WITH CONTEXT ===
"Account Executive at Google": ["Account Executive"],
"Senior Account Executive, Enterprise": ["Senior Account Executive"],
"BDR - North America": ["Business Development Representative"],
"SDR, EMEA": ["Sales Development Representative"],
# === SALES ROLES COMBINED WITH OTHER ROLES ===
"Account Executive and BDR": ["Account Executive", "Business Development Representative"],
"SDR/BDR": ["Sales Development Representative", "Business Development Representative"],
"Senior AE & VP": ["Senior Account Executive", "VP"],
# === C-LEVEL CATCH-ALL (Unknown C-level roles) ===
"Chief Data Officer": ["C Level"],
"chief data officer": ["C Level"],
"Chief Strategy Officer": ["C Level"],
"Chief Legal Officer": ["C Level"],
"Chief Administrative Officer": ["C Level"],
"Chief Customer Officer": ["C Level"],
"Chief Digital Officer": ["C Level"],
"Chief Compliance Officer": ["C Level"],
"Chief Investment Officer": ["C Level"],
"Chief Experience Officer": ["C Level"],
"Chief Accounting Officer": ["C Level"],
"Chief Analytics Officer": ["C Level"],
"Chief Security Officer": ["C Level"],
"Chief Innovation Officer": ["C Level"],
"Chief Sustainability Officer": ["C Level"],
"Chief Risk Officer": ["C Level"],
"Chief Communications Officer": ["C Level"],
"Chief Content Officer": ["C Level"],
"Chief Knowledge Officer": ["C Level"],
"Chief Procurement Officer": ["C Level"],
# C-Level catch-all with context
"Chief Data Officer at Google": ["C Level"],
"Former Chief Strategy Officer": ["C Level"],
"Interim Chief Legal Officer": ["C Level"],
# C-Level catch-all combined with other roles
"Chief Data Officer and Board Member": ["C Level", "Board Member"],
"VP and Chief Strategy Officer": ["VP", "C Level"],
# === EXISTING C-LEVEL ROLES SHOULD NOT GET "C Level" ===
# (These tests verify existing C-level roles remain unchanged)
# Already tested above, but adding explicit verification:
# "CEO": ["CEO"], # Should NOT be ["CEO", "C Level"] - already tested
# "CTO": ["CTO", "CITPO"], # Should NOT include "C Level" - already tested
# "CFO": ["CFO"], # Should NOT include "C Level" - already tested
}
# Variables to track test results
all_passed = True
passed_count = 0
total_count = len(test_titles)
# Print header for test results
print("=" * 80)
print("COMPREHENSIVE ROLE NORMALIZER TEST SUITE")
print("=" * 80)
# Run each test case
for title, expected in test_titles.items():
# Get the actual result from our normalizer
result = normalizer.normalize_employee_title(title)
# Check if it matches what we expected
passed = (result == expected)
# Count successful tests
if passed:
passed_count += 1
status = "✅" # Green checkmark for pass
else:
status = "❌" # Red X for fail
# Print the test result
print(f"{status} Raw: '{title}' → Normalized: '{result}' | Expected: '{expected}'")
# Track if any tests failed
if not passed:
all_passed = False
# Print final summary
print("=" * 80)
print(f"RESULTS: {passed_count}/{total_count} tests passed")
print(f"SUCCESS RATE: {(passed_count/total_count)*100:.1f}%")
print(f"OVERALL: {'✅ ALL TESTS PASSED' if all_passed else '❌ SOME TESTS FAILED'}")
print("=" * 80)Editor is loading...
Leave a Comment