"""队名归一化:各源队名 → 统一规范名。 迁移自旧项目 app/data/team_names.py。 NFKD 归一化会剥离变音符号(ü→u),导致「Bayern München」与「Bayern Munich」 映射到不同规范名。修复:双重查找(原始名 + NFKD 名) + 补齐常见变体键。 """ from __future__ import annotations import unicodedata NORMALIZE_MAP = { # ---- 英超 ---- "Man City": "Manchester City", "Man United": "Manchester United", "Newcastle": "Newcastle United", "Nott'm Forest": "Nottingham Forest", "Wolves": "Wolverhampton Wanderers", "West Ham": "West Ham United", "Tottenham": "Tottenham Hotspur", "Spurs": "Tottenham Hotspur", "Brighton": "Brighton and Hove Albion", "West Brom": "West Bromwich Albion", "Stoke": "Stoke City", "Huddersfield": "Huddersfield Town", "Swansea": "Swansea City", "Hull": "Hull City", "Cardiff": "Cardiff City", "Luton": "Luton Town", "Norwich": "Norwich City", "Bournemouth": "AFC Bournemouth", "Ipswich": "Ipswich Town", "Leicester": "Leicester City", "Leeds": "Leeds United", "Sheffield United": "Sheffield United", "Southampton": "Southampton", "Arsenal": "Arsenal", "Aston Villa": "Aston Villa", "Brentford": "Brentford", "Chelsea": "Chelsea", "Crystal Palace": "Crystal Palace", "Everton": "Everton", "Fulham": "Fulham", "Liverpool": "Liverpool", # ---- 西甲 ---- "Atletico Madrid": "Atlético Madrid", "Athletic Club": "Athletic Club", "Real Betis": "Real Betis", "Celta Vigo": "Celta Vigo", "Deportivo Alaves": "Deportivo Alavés", "Girona": "Girona", "Las Palmas": "Las Palmas", "Leganes": "Leganés", "Mallorca": "Mallorca", "Osasuna": "Osasuna", "Rayo Vallecano": "Rayo Vallecano", "Real Sociedad": "Real Sociedad", "Sevilla": "Sevilla", "Valencia": "Valencia", "Villarreal": "Villarreal", "Espanyol": "Espanyol", "Getafe": "Getafe", "Real Madrid": "Real Madrid", "Barcelona": "Barcelona", # ---- 德甲 ---- "Bayern Munich": "Bayern München", "Bayern Munchen": "Bayern München", # NFKD stripped variant "Bayern München": "Bayern München", # canonical with umlaut (direct hit) "FC Koln": "FC Köln", "FC Köln": "FC Köln", "RB Leipzig": "RB Leipzig", "Borussia Dortmund": "Borussia Dortmund", "Borussia M'gladbach": "Borussia Mönchengladbach", "Borussia Monchengladbach": "Borussia Mönchengladbach", # NFKD stripped "Borussia Mönchengladbach": "Borussia Mönchengladbach", # canonical "Bayer Leverkusen": "Bayer Leverkusen", "Eintracht Frankfurt": "Eintracht Frankfurt", "VfB Stuttgart": "VfB Stuttgart", "VfL Wolfsburg": "VfL Wolfsburg", "Werder Bremen": "Werder Bremen", "TSG Hoffenheim": "TSG Hoffenheim", "SC Freiburg": "SC Freiburg", "Union Berlin": "Union Berlin", "Mainz": "Mainz 05", "Augsburg": "FC Augsburg", "Bochum": "VfL Bochum", "Heidenheim": "1. FC Heidenheim", "St. Pauli": "FC St. Pauli", "Holstein Kiel": "Holstein Kiel", # ---- 意甲 ---- "AC Milan": "AC Milan", "Inter": "Inter Milan", "Inter Milan": "Inter Milan", "Juventus": "Juventus", "Napoli": "SSC Napoli", "Roma": "AS Roma", "Lazio": "Lazio", "Atalanta": "Atalanta", "Fiorentina": "ACF Fiorentina", "Bologna": "Bologna", "Torino": "Torino", "Monza": "AC Monza", "Udinese": "Udinese", "Sassuolo": "Sassuolo", "Empoli": "Empoli", "Cagliari": "Cagliari", "Genoa": "Genoa", "Lecce": "Lecce", "Hellas Verona": "Hellas Verona", "Parma": "Parma", "Como": "Como", "Venezia": "Venezia", # ---- 法甲 ---- "PSG": "Paris Saint-Germain", "Paris Saint-Germain": "Paris Saint-Germain", "Marseille": "Olympique Marseille", "Lyon": "Olympique Lyonnais", "Monaco": "AS Monaco", "Lille": "Lille OSC", "Nice": "OGC Nice", "Rennes": "Stade Rennais", "Lens": "RC Lens", "Strasbourg": "RC Strasbourg", "Brest": "Stade Brestois", "Nantes": "FC Nantes", "Reims": "Stade de Reims", "Toulouse": "Toulouse FC", "Montpellier": "Montpellier HSC", "Le Havre": "Le Havre AC", "Lorient": "FC Lorient", "Saint-Etienne": "AS Saint-Étienne", "Saint-Etienne": "AS Saint-Étienne", # NFKD stripped (ê → e) "AS Saint-Étienne": "AS Saint-Étienne", # canonical prefix "AS Saint-Etienne": "AS Saint-Étienne", # NFKD stripped with prefix "Angers": "Angers SCO", "Auxerre": "AJ Auxerre", "Leganes": "Leganés", } def normalize(name: str) -> str: """队名归一化:变音符号变体 → 统一规范名。 双重查找策略: 1. 原始名(带变音)直接查表 2. NFKD 去变音后再查表 确保「Bayern München」「Bayern Munchen」「Bayern Munich」 都映射到同一规范名「Bayern München」。 """ if not name: return "" # 1. 原始名直接查表(保留变音变体) stripped = name.strip() if stripped in NORMALIZE_MAP: return NORMALIZE_MAP[stripped] # 2. NFKD 去变音后查表 n = unicodedata.normalize("NFKD", stripped) n = "".join(c for c in n if not unicodedata.combining(c)) n = n.strip() return NORMALIZE_MAP.get(n, n)