eb8dbf66a1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
2.4 KiB
Python
71 lines
2.4 KiB
Python
"""Convierte un nombre/titulo de Obsidian a un slug kebab-case estable.
|
|
|
|
Funcion pura: transliteracion Unicode + normalizacion a [a-z0-9-]. No hace I/O.
|
|
"""
|
|
|
|
import re
|
|
import unicodedata
|
|
|
|
# Cualquier secuencia de caracteres que NO sea [a-z0-9] colapsa a un solo '-'.
|
|
_NON_SLUG_RE = re.compile(r"[^a-z0-9]+")
|
|
|
|
# Mapeo explicito de caracteres que NFKD no descompone como queremos.
|
|
_TRANSLIT_MAP = {
|
|
"ñ": "n",
|
|
"Ñ": "n",
|
|
}
|
|
|
|
|
|
def slugify_obsidian_name(name: str) -> str:
|
|
"""Convierte un nombre o titulo a un slug kebab-case estable.
|
|
|
|
Pasos, en orden:
|
|
1. Mapea caracteres especiales que NFKD no descompone (ñ/Ñ -> n).
|
|
2. Normaliza con ``unicodedata.normalize('NFKD', ...)`` y descarta los
|
|
combining marks (acentos, diacriticos), transliterando a ASCII.
|
|
3. Pasa todo a minusculas.
|
|
4. Reemplaza cualquier secuencia de caracteres no ``[a-z0-9]`` por un
|
|
unico ``-``.
|
|
5. Hace strip de ``-`` al inicio y al final. Nunca quedan guiones dobles.
|
|
|
|
Es deterministica y pura: misma entrada -> mismo slug, sin efectos
|
|
secundarios ni I/O.
|
|
|
|
Args:
|
|
name: Nombre o titulo arbitrario (puede llevar acentos, mayusculas,
|
|
espacios, simbolos).
|
|
|
|
Returns:
|
|
El slug kebab-case correspondiente. Cadena vacia si ``name`` no
|
|
contiene ningun caracter slugificable.
|
|
"""
|
|
if not name:
|
|
return ""
|
|
|
|
# 1. Mapeo explicito antes de NFKD (la cedilla de la enye se trataria mal).
|
|
for src, dst in _TRANSLIT_MAP.items():
|
|
name = name.replace(src, dst)
|
|
|
|
# 2. Transliteracion Unicode: descompone y descarta combining marks.
|
|
decomposed = unicodedata.normalize("NFKD", name)
|
|
ascii_only = "".join(ch for ch in decomposed if not unicodedata.combining(ch))
|
|
|
|
# 3. Minusculas.
|
|
lowered = ascii_only.lower()
|
|
|
|
# 4. Colapsar todo lo no [a-z0-9] a un unico '-'.
|
|
slug = _NON_SLUG_RE.sub("-", lowered)
|
|
|
|
# 5. Strip de guiones en los bordes.
|
|
return slug.strip("-")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
assert slugify_obsidian_name("Enmanuel Gutiérrez Pérez") == "enmanuel-gutierrez-perez"
|
|
assert slugify_obsidian_name("Jose manuel camaño castro") == "jose-manuel-camano-castro"
|
|
assert slugify_obsidian_name("DNI de María del Mar") == "dni-de-maria-del-mar"
|
|
assert slugify_obsidian_name(" raro__nombre!! ") == "raro-nombre"
|
|
assert slugify_obsidian_name("") == ""
|
|
assert slugify_obsidian_name("!!!") == ""
|
|
print("slugify_obsidian_name smoke OK")
|