"""Extrae FQDNs validos de un texto, con offsets.""" import re # Lista estatica de TLDs comunes (no exhaustiva — IANA tiene >1500). # Incluye los gTLD originales, los nuevos mas usados, y ccTLD frecuentes. _VALID_TLDS = frozenset({ # gTLD originales "com", "org", "net", "edu", "gov", "mil", "int", # gTLD comunes "info", "biz", "name", "pro", "mobi", "asia", "jobs", "tel", "travel", "xxx", "post", # nuevos gTLD populares "app", "dev", "io", "ai", "tech", "cloud", "online", "site", "store", "xyz", "top", "shop", "club", "fun", "live", "blog", "page", "news", "media", "design", "studio", "agency", "io", "co", "me", "tv", # ccTLD frecuentes "us", "uk", "de", "fr", "es", "it", "nl", "be", "se", "no", "fi", "dk", "ru", "ua", "pl", "cz", "ch", "at", "pt", "gr", "ie", "tr", "ca", "mx", "br", "ar", "cl", "co", "pe", "ve", "uy", "cn", "jp", "kr", "in", "id", "th", "vn", "my", "sg", "ph", "tw", "hk", "au", "nz", "za", "eg", "ma", "ng", "ke", "il", "ae", "sa", "qa", "eu", }) # Componentes: letras/digitos con guiones internos, sin empezar/terminar en guion. _LABEL = r"[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?" _DOMAIN_REGEX = re.compile( rf"(? list[dict]: """Extrae FQDNs cuyo TLD esta en la lista estatica. Solo captura nombres con al menos un punto y un TLD reconocido. No incluye URLs completas (ver `extract_urls`). Si el dominio aparece dentro de un email, igual se extrae — el caller puede deduplicar por offsets si lo necesita. """ results = [] for m in _DOMAIN_REGEX.finditer(text): candidate = m.group(0) tld = candidate.rsplit(".", 1)[-1].lower() if tld not in _VALID_TLDS: continue results.append({ "value": candidate, "start": m.start(), "end": m.end(), "type": "domain", }) return results