"""Extrae numeros de telefono (E.164 + formatos comunes ES/EU) con offsets.""" import re # E.164: + seguido de 8 a 15 digitos, opcionalmente con espacios/guiones internos. _E164_REGEX = re.compile( r"(? list[dict]: """Extrae numeros de telefono E.164 y formato local ES de 9 digitos. Acepta separadores `space`, `-` entre grupos. E.164 requiere `+` y entre 8 y 15 digitos (ITU-T). Formato local ES son 9 digitos que empiezan por 6/7/8/9. Tras quitar separadores se valida la longitud minima. """ seen_spans = set() results = [] for m in _E164_REGEX.finditer(text): candidate = m.group(0) digits = re.sub(r"[^0-9]", "", candidate) if not (8 <= len(digits) <= 15): continue span = (m.start(), m.end()) if span in seen_spans: continue seen_spans.add(span) results.append({ "value": candidate, "start": m.start(), "end": m.end(), "type": "phone_number", }) for m in _ES_LOCAL_REGEX.finditer(text): candidate = m.group(0) digits = re.sub(r"[^0-9]", "", candidate) if len(digits) != 9: continue span = (m.start(), m.end()) if span in seen_spans: continue seen_spans.add(span) results.append({ "value": candidate, "start": m.start(), "end": m.end(), "type": "phone_number", }) results.sort(key=lambda r: r["start"]) return results