Módulo:generar-pron/ast

La documentación para este módulo puede ser creada en Módulo:generar-pron/ast/doc

--Autor: Tmagc
--Adaptado de Módulo:generar-pron/es y revisado por Limotecariu

local export = {}

local insert = table.insert
local concat = table.concat

local m_table = require("Módulo:tabla")

local m_str = require("Módulo:String")

local u = m_str.char
local strfind = m_str.find
local strsubn = m_str.gsub
local strsubb = m_str.gsubb
local strmatchit = m_str.gmatch
local strsubrep = m_str.gsub_rep
local strsplit = m_str.split
local strupper = m_str.upper
local strlower = m_str.lower
local strucfirst = m_str.ucfirst
local strnfd = m_str.toNFD
local strnfc = m_str.toNFC
local strstrip = m_str.strip
local substr = m_str.sub
local strlen = m_str.len
local strexplode = m_str.explode_utf8

local function strsub(s, a, b)
	local c, _ = strsubn(s, a, b)
	return c
end

--CONVENCION: mayúscula para patrones encerrados entre corchetes, minúscula para todo lo demás
local ag = u(0x0301) -- acute =  ́
local gr = u(0x0300) -- grave =  ̀
local circunflejo = u(0x0302) -- circumflex =  ̂
local virgulilla = u(0x0303) -- tilde =  ̃
local dieresis = u(0x0308) -- diaeresis =  ̈
local punto_subscrito = u(0x323) -- cambia la pronunciación de la "h" y la "ll"
local ac_primario = u(0x02C8)
local ac_secundario = u(0x02CC)

local diacritico = ag .. gr .. circunflejo
local DIACRITICO = "[" .. diacritico .. "]"
local tilde = ag .. gr
local TILDE = "[" .. tilde .. "]"
local acentos_ipa = ac_primario..ac_secundario
local ACENTOS_IPA = "[" .. acentos_ipa .. "]"

local divsil = u(0xFFF0)
local divsil_fijo = u(0xFFF1)
local sepsil = "%-." .. divsil .. divsil_fijo
local SEPARADORES_SILABICOS = "[" .. sepsil .. "]"
local SALVO_SEPARADORES_SILABICOS = "[^" .. sepsil .. "]"
local seppal = "# "
local separador_excepto_palabras = diacritico .. acentos_ipa .. sepsil
local separador = separador_excepto_palabras .. seppal
local SEPARADOR = "[" .. separador .. "]"

local vocales = "aeiouüAEIOUÜ"
local VOCAL = "[" .. vocales .. "]"
local vocales_tildadas = "áéíóúàèìòùÁÉÍÓÚÀÈÌÒÙ"
local VOCAL_TILDADA = "[" .. vocales_tildadas .. "]"
local CONS = "[^" .. vocales .. vocales_tildadas .. separador .. "]"
local CONS_SALVO_H = "[^" .. vocales .. vocales_tildadas .. separador .. "h]"
local CONS_O_SEP_PALABRA = "[^" .. vocales .. vocales_tildadas .. separador_excepto_palabras .. "]"
--local T = "[^" .. vocales .. "lrɾjw" .. separador .. "]" -- obstruent or nasal

-- Para las notas al pie
local VOCAL_GENERAL = "[" .. vocales .. vocales_tildadas .. "]"

local PUNTUACION = "[%(%)%[%]%{%}¡!¿?.,;:–—]"
local PUNTUACION_EXTRA = "[%(%)%[%]%{%}¡!¿?.,;:–—\"“”„‟‘’«»»«‹››‹'´]"

local TEMP_I = u(0xFFF1)
local TEMP_J = u(0xFFF2)
local TEMP_U = u(0xFFF3)
local TEMP_Y_CONS = u(0xFFF4)
local TEMP_QU = u(0xFFF5)
local TEMP_QU_CAPS = u(0xFFF6)
local TEMP_GU = u(0xFFF7)
local TEMP_GU_CAPS = u(0xFFF8)
local TEMP_H = u(0xFFF9)
local TEMP_Y = u(0xFFFA)
local TEMP_W = u(0xFFFB)
local TEMP_TCHR = u(0xFFFC)
local foot_boundari = "|"
local terminador = "#"
local comodin_yeista = "ɟ"
local comodin_chancho = "ĉ"
local comodin_jota = "ħ"
local comodin_deshielo = "ĥ"

local COMODINES = "[" .. TEMP_I .. TEMP_J .. TEMP_U .. TEMP_Y_CONS .. TEMP_QU .. TEMP_QU_CAPS .. TEMP_GU .. TEMP_GU_CAPS .. TEMP_H .. TEMP_Y .. TEMP_W .. TEMP_TCHR ..
comodin_yeista .. comodin_chancho .. comodin_jota .. comodin_deshielo .. "g" .. "%" .. foot_boundari .. terminador .. "]"

local recuperar_comodin = {
    [TEMP_I] = "i",
	[TEMP_J] = "i", -- i como semivocal
    [TEMP_U] = "u",
    [TEMP_Y_CONS] = "y",
    [TEMP_QU] = "qu",
    [TEMP_QU_CAPS] = "Qu",
    [TEMP_GU] = "gu",
    [TEMP_GU_CAPS] = "Gu",
    [TEMP_H] = "h", -- h que no se aspirada
    [TEMP_Y] = "i", --sufijos -ay/-ey/-oy/-uy
	[TEMP_W] = "w̝", -- hueso, huevo, etc. (la otra w ya la procesamos antes)
	[TEMP_TCHR] = "tchr",
	[comodin_jota] = "h",  -- fake aspirated "h" to real "h"
	[comodin_chancho] = "t͡ʃ", -- fake "ch" to real "ch"
	[comodin_yeista] = "ʝ", --phonetic and "ɟ͡ʝ" or "ʝ", -- fake "y" to real "y
	[comodin_deshielo] = "desh",
	["g"] = "ɡ", -- U+0067 LATIN SMALL LETTER G → U+0261 LATIN SMALL LETTER SCRIPT G
	[foot_boundari] = "|",
	[terminador] = "",
}

local recuperar_comodin_silabeo = {
    [TEMP_I] = "i",
	[TEMP_J] = "i", -- i como semivocal
    [TEMP_U] = "u",
    [TEMP_Y_CONS] = "y",
    [TEMP_QU] = "qu",
    [TEMP_QU_CAPS] = "Qu",
    [TEMP_GU] = "gu",
    [TEMP_GU_CAPS] = "Gu",
    [TEMP_H] = "h", -- h que no se aspirada
    [TEMP_Y] = "i", --sufijos -ay/-ey/-oy/-uy
	[TEMP_W] = "u", -- hueso, huevo, etc. (la otra w ya la procesamos antes)
	[TEMP_TCHR] = "tchr",
	[comodin_jota] = "h",  -- fake aspirated "h" to real "h"
	[comodin_chancho] = "ch", -- fake "ch" to real "ch"
	[comodin_yeista] = "y", --phonetic and "ɟ͡ʝ" or "ʝ", -- fake "y" to real "y
	[comodin_deshielo] = "desh",
	["ɡ"] = "g", -- AL REVÉS QUE EN LA OTRA TABLA
	[foot_boundari] = "|",
	[terminador] = "",
}


local no_acentuado = m_table.listToSet({
	"el", "la", "los", "las", -- artículos
	"me", "te", "se", "nos", "vos", "lu", "la", "lo", "los", "les", -- pron. objeto
	"que", "quien", "como", "cuando", "onde", "u", "au", "cuantu", "cuanta", "cuanto", "cuantos", "cuantes", -- pron. relativos
	"y", "ya", "o", "u", "nin", -- conjunciones
	"de", "del", "a", "al", -- preposiciones y articulos
	"por", "en", "con", "sin", "tras", -- más preposiciones
	--"mas", --pero REVISAR, hay otro “mas”
	"so", --de so pretexto
	"si", -- ??
--	"sol", "col", "cola", "colo", "coles", "polos", "pela", "pelo", "pelos", "peles" REVISAR, puede haber variantes tónicas
})

-- aislar_diacriticos salvo ñ, ü y los puntos subscritos
local function aislar_diacriticos(text)
	text = strnfd(text)
	text = strsubn(text, ".[" .. virgulilla .. dieresis .. punto_subscrito .. "]", {
		["n" .. virgulilla] = "ñ",
		["N" .. virgulilla] = "Ñ",
		["u" .. dieresis] = "ü",
		["U" .. dieresis] = "Ü",
		["h" .. punto_subscrito] = "ḥ",
		["H" .. punto_subscrito] = "Ḥ",
		["l" .. punto_subscrito] = "ḷ",
		["L" .. punto_subscrito] = "Ḷ",
	})
	return text
end

local function quitar_diacriticos(text) -- salvo virgulilla y diéresis
	text = strnfd(text)
	text = strsubn(text, "[" .. ag .. gr .. circunflejo .. ac_primario .. ac_secundario .. "]", "")
	return strnfc(text)
end
-- convert i/u between vowels to glide
local vowel_to_glide = { ["i"] = "j", ["u"] = "w" }
local vowel_to_glide_silabeo = { ["i"] = TEMP_J, ["u"] = TEMP_W }
	
local tildar = {
	["a"] = "á",
	["e"] = "é",
	["i"] = "í",
	["o"] = "ó",
	["u"] = "ú",
}

local quitar_tilde = {
	["á"] = "a",
	["é"] = "e",
	["í"] = "i",
	["ó"] = "o",
	["ú"] = "u",
}

local diacritico_a_IPA = { [ag] = ac_primario, [gr] = ac_secundario, [circunflejo] = "" }
local pron_abc = {{"a"},{"be"},{"ce"},{"de"},{"e"},{"efe"},{"gue"},{"hache"},{"i"},
	{"jota","yota"},{"ka"},{"ele"},{"eme"},{"ene"},{"o"},{"pe"},{"cu"},{"erre"},{"ese"},{"te"},{"u"},
	{"uve"},{"uve doble"},{"xe","equis"},{"ye","y griega"},{"zeta","zeda"},{"eñe"}}

local function normalizar(texto)
	texto = strlower(texto)
	texto = aislar_diacriticos(texto)
	texto = strsubrep(texto, PUNTUACION, " | ") -- convierto lo que delimite fragmentos a los IPA foot boundaries |
	texto = strsubrep(texto, PUNTUACION_EXTRA, "") -- elimino la puntuación restante que haya quedado
	texto = strsubrep(texto, "[%-‐](yo?s?)", "%1") -- sustituyo pronombres pospuestos con guion (-y/-yos/-ys)
	texto = strsubrep(texto, "[%-‐]", " ") --los guiones pasan a ser espacios (austro-húngaro, franco-italiano)

    texto = strsubrep(texto, "%s*|%s*|%s*", " | ") --finalmente, elimino las barras y espacios de más
    texto = strsubrep(texto, "%s+", " ")
	texto = strstrip(texto, "[%s|]+")
	
	return texto
end

local function determinar_acentuacion(acento_id)
	if acento_id then
		if acento_id == -1 then
			return "monosílaba"
		elseif acento_id == 0 then
			return "doble acentuada"
		elseif acento_id == 1 then
			return "aguda"
		elseif acento_id == 2 then
			return "llana"
		elseif acento_id == 3 then
			return "esdrújula"
		elseif acento_id >= 4 then
			return "sobreesdrújula"
		else
			return nil
		end
	else
		return nil
	end
end

--Convierte los diacríticos a notación IPA
local function reemplazar_tildes(w)
	local silabas = strsplit(w, SEPARADORES_SILABICOS)
	local L = #silabas
	local sufijo = nil
	
	if L >= 4 and silabas[L-1] == "men" and silabas[L] == "te" then
		sufijo = {ac_primario.."men", divsil.."te"}
		silabas[L-1], silabas[L] = nil, nil
		L = L - 2
	end
	
	local sustituido = false
	local sust = false
	
	for i,silaba in ipairs(silabas) do
		silabas[i], sust = strsubb(silaba, "^(.*)(" .. DIACRITICO .. ")(.*)$",	function(pre, diacr, post) return diacritico_a_IPA[diacr] .. pre .. post end)
		sustituido = sustituido or sust
	end
	
	if not sustituido then
		if L > 1 then
			if strfind(w, "[^" .. vocales .. "ns]$") or strfind(w, CONS..CONS.."$") then -- las palabras que terminan en doble consonante son agudas a menos que lleven tilde https://www.rae.es/espanol-al-dia/por-que-biceps-se-escribe-con-tilde-si-es-una-palabra-llana-terminada-en-s
				silabas[L] = ac_primario .. silabas[L] --aguda
			else
				silabas[L - 1] = ac_primario .. silabas[L - 1] --grave
			end
		else --Si L==1, entonces el monosílabo es tónico ya que no tiene circunflejos
			silabas[1] = ac_primario .. silabas[1]
		end 
	end
	
	local p = silabas[1]
	
	for i,s in ipairs(silabas) do
		if i > 1 then
			if strfind(s, ACENTOS_IPA) then
				p = p .. s
			else
				p = p .. divsil .. s
			end
		end
	end
	
	if sufijo then
		return p .. sufijo[1] .. sufijo[2]
	else
		return p
	end
end

--Se obtiene la longitud silábica, acentuación (hacerlo con la ayuda, no con el original)
local function obtener_informacion(w)
	if type(w) ~= "string" then
		return nil	
	end
	local silabas = strsplit(w, SEPARADORES_SILABICOS)
	
	local L = #silabas
	local sufijo = nil
	if L >= 4 and silabas[L-1] == "men" and silabas[L] == "te" then
		sufijo = "-men-te"
		silabas[L-1], silabas[L] = nil, nil
		L = L - 2
	end
	
	local acento_id = nil
	local acento_idx = nil
	local lleva_tilde = nil
	
	for i,silaba in ipairs(silabas) do
		lleva_tilde = strfind(silaba, "^(.*)(" .. VOCAL_TILDADA .. ")(.*)$")
		if lleva_tilde then
			acento_id = L == 1 and -1 or L - i + 1
			acento_idx = i
			break
		end
	end
	
	if not lleva_tilde then
		if L == 1 then
			acento_id = -1 --monosílabo
			acento_idx = 1
		else
			if strfind(w, "[^" .. vocales .. "ns]$") or strfind(w, CONS..CONS.."$") then -- las palabras que terminan en doble consonante son agudas a menos que lleven tilde https://www.rae.es/espanol-al-dia/por-que-biceps-se-escribe-con-tilde-si-es-una-palabra-llana-terminada-en-s
				acento_id = 1 -- aguda
				acento_idx = L
			else
				acento_id = 2 -- grave
				acento_idx = L - 1
			end
		end
	end
	
	if sufijo then --por ahora el único caso contemplado son los adverbios que terminan en -mente
		return L + 2, determinar_acentuacion(0), "ente" --0 para indicar doble acentuación
	else
		local x = nil
		if lleva_tilde then
			x = strfind(silabas[acento_idx], VOCAL_TILDADA)
			if not x then
				return nil,nil
			end
		else
			x = strfind(silabas[acento_idx], VOCAL)
			if not x then
				return nil,nil
			end
			local q = substr(silabas[acento_idx], x-1, x+1)
			if q == "que" or q == "qui" or q == "gue" or q == "gui" then
				x = x+1
			end
		end
		return L, determinar_acentuacion(acento_id)
	end
end

--Pasos finales al dividir en sílabas (2 puntos de entrada: la función de generar
--pronunciación y la que separa en sílabas propiamente dicha)
local function separar_en_silabas_final(word)
	
	--PASO 1: Divida tras cada grupo de vocales + última consonante que no sea h, o bien entre consonantes que estén
	--rodeades por vocales, pero sin contar la 'h' (prohibir --> prohi.bir)
	
	word = strsubrep(word, "(" .. VOCAL .. DIACRITICO .. "*)(" .. CONS_SALVO_H .. VOCAL .. ")", "%1"..divsil.."%2")
	word = strsubrep(word, "(" .. VOCAL .. DIACRITICO .. "*" .. CONS .. "+)(" .. CONS .. VOCAL .. ")", "%1"..divsil.."%2")

	--PASO 2: Vuelva a juntar algunos grupos de consonantes
	
	-- Juntar consonantes fricativas y oclusivas con l y con r. A ecepción de dl. --> En asturiano también existe "zr", existe dl??
	word = strsubn(word, "([zpbfvkctg])"..divsil.."([lrɾ])", divsil.."%1%2")
	word = strsubn(word, "d%"..divsil.."([rɾ])", divsil.."d%1")
	
	 -- swing, switch, etc.
	word = strsubn(word, "s"..divsil.."w", divsil.."sw")
	-- Juntar ch, sh, zh, ph, th, dh, fh, kh or gh. NO Juntar bh (subhumano, subhúmedo)
	word = strsubn(word, "([cszptdfkg])"..divsil.."h", divsil.."%1h")
	-- Juntar las ll y rr
	word = strsubn(word, "l"..divsil.."l", divsil.."ll")
	word = strsubn(word, "r"..divsil.."r", divsil.."rr")
	
	-- Juntar -uyir
	word = strsubn(word, "u"..divsil..TEMP_Y_CONS.."i([ɾr])$", "u"..TEMP_Y_CONS.."i%1")
	word = strsubn(word, "u"..divsil..comodin_yeista.."i([ɾr])$", "u"..comodin_yeista.."i%1")
	
	-- Juntar tz (([[Ertzaintza]], [[quetzal]], [[hertziano]], palabras Vascas, Nahualt o Alemanas) -- dudo de que sea lo correcto
	word = strsubn(word, "t"..divsil.."z", divsil.."tz")

	-- PASO 3: separar los hiatos 
	-- vocal abierta + vocal abierta (opcional h)
	word = strsubrep(word, "([aeoAEO]" .. DIACRITICO .. "*)(h?[aeo])", "%1"..divsil.."%2")
	-- vocal + vocal tildada
	word = strsubrep(word, "("..VOCAL .. DIACRITICO .. "*)(h?" .. VOCAL .. TILDE .. ")", "%1"..divsil.."%2")
	-- vocal tildada + vocal
	word = strsubn(word, "(" .. VOCAL .. TILDE .. ")(h?"..VOCAL..")", "%1"..divsil.."%2")
	
	-- verbos en -uir
	word = strsubn(word, "ui([ɾr])$", "u"..divsil.."i%1")

	-- Finalmente, vuelvo a juntar vocales repetidas (en asturiano, en general las vocales dobles se simplifican)
	word = strsubn(word, "("..VOCAL..")("..TILDE.."?)"..divsil.."(h?%1)", "%1%2%3")

	word = strsub(word, SEPARADORES_SILABICOS.."+", divsil)
	word = strstrip(word, SEPARADORES_SILABICOS.."+")

	return word
end

-- FUNCION QUE DIVIDE EN SILABAS (SÓLO PARA UNA PALBRA; SI HAY VARIAS PALABRAS HACERLO DE A UNA POR VEZ POR FAVOR)
local function separar_en_silabas(w)
	if type(w) ~= "string" or strfind(w, "%s") then
		return nil
	end
	
	local p = normalizar(w)
	
	p = strsubn(p, "|", "")
	p = strsubrep(p, "%s+", divsil_fijo) --cambio espacio normalizado por divisor de sílaba fijo
	
	p = strsubn(p, "y(" .. VOCAL .. ")", TEMP_Y_CONS .. "%1")
	
	--Cambio tchr por el comodin
	p = strsubn(p, "tchr", TEMP_TCHR)

	-- Mantenemos junta la 'sh' cuando se trate de desh- (deshuesar, deshonra, deshecho), en los demás casos la separamos.
	-- Para hacerlo, cambiamos la h en los segundos casos
	p = strsubn(p, "^([Dd]es)h", "%1" .. TEMP_H)
	p = strsubn(p, "([ %-][Dd]es)h", "%1" .. TEMP_H)

	-- Cambiamos 'qu' y 'gu'
	-- Dicen que 'qu' va bien reemplazarlo, pero hace agua con 'quietud'
	p = strsubn(p, "qu(" .. VOCAL .. ")", TEMP_QU .. "%1")
	p = strsubn(p, "Qu(" .. VOCAL .. ")", TEMP_QU_CAPS .. "%1")
	p = strsubn(p, "gu(" .. VOCAL .. ")", TEMP_GU .. "%1")
	p = strsubn(p, "Gu(" .. VOCAL .. ")", TEMP_GU_CAPS .. "%1")

	--Agregamos glides (paranoia, baiano, abreuense, alauita, Malaui, marihuana, parihuela, antihielo, pelluhuano, náhuatl)
	--NOTA IMPORTANTE: conviene hacerlo de atrás hacia adelante para que no se generen cosas raras como 'an.tih.ie.lo'

	p = strsubrep(p, "(.*" .. VOCAL .. DIACRITICO .. "*)(h?)([iu])(" .. VOCAL .. ")",function (v1, h, iu, v2) return v1 .. divsil .. h .. vowel_to_glide_silabeo[iu] .. v2 end)

	-- Entro a la función que separa ya pre-procesado a formato IPA
	p = separar_en_silabas_final(p)
	
	p = strsubn(p, COMODINES, recuperar_comodin_silabeo)
	p = strsubn(p, divsil, "-")
	return strnfc(p)
end

-- EXPORTAR A IPA. Es decir, ya teniendo el texto re-escrito para facilitar la pronunciación.
local function generar_pron(text, phonetic)
	if type(text) ~= "string" then
		return {},{}
	end
	
	text = normalizar(text)
	
	--Comienzo a sustituir
	--Observación general: el orden en el que sustituimos importa
	
	-- Make prefixes unstressed unless they have an explicit stress marker; also make certain
	-- monosyllabic words (e.g. [[el]], [[la]], [[de]], [[en]], etc.) without stress marks be
	-- unstressed.
	local words = strsplit(text, " ")
	for i, word in ipairs(words) do
		if no_acentuado[word] then
			words[i] = strsubn(word, "^(.*" .. VOCAL .. ")", "%1" .. circunflejo) --pongo el circunflejo para indicar que no debe haber acentuación
		end
	end
	-- put # at word beginning and end and double ## at text/foot boundary beginning/end
	text = concat(words, " ")
	text = strsubn(text, " | ", "# | #")
	text = "##" .. strsubn(text, " ", "# #") .. "##"

	--determinar el sonido apropiado para la y
	-- Nota: sufijos -ay/-ey/-oy/-uy se acentúan, pero no -ai/-ei/-oi/-ui
	-- Nota: -uy mapea a /uj/ mientras que -ui mapea a /wi/
	
	text = strsubb(text, "y(" .. VOCAL .. ")", comodin_yeista.."%1") -- ɟ -> comodín del yeísmo
	
	--Esto no es conveniente hacerlo
	--text = strsubn(text, "([aeou])y#", "%1" .. TEMP_Y .. "#") -- pongo marca privada por el momento
	--text = strsubn(text, "y", "i")

	--Necesitamos procesar sh/ch justo acá (para no hacer lío con la x exhausto (??))
	text = strsubn(text, "ch", comodin_chancho) -- otro comodín más
	text = strsubn(text, "#desh", comodin_deshielo) --comodín para preservar 'desh' (deshuesar, etc.)
	text = strsubn(text, "sh", "ʃ") --reemplazo sh
	text = strsubn(text, "zh", "ʒ") --reemplazo zh
	text = strsubn(text, comodin_deshielo, "#desh") --restauro desh
	text = strsubn(text, "#p([st])", "#%1") -- Saco la p inicial de psicología o pterodáctilo
	text = strsubn(text, "#[mg]n", "#n") -- Saco la g inicial de gnoseología y la m de mnemónico
	
	--tl al final de la palabra
	text = strsubn(text, "tl#", "t#")

	--x
	-- text = strsubn(text, "#x", "#s") -- reemplazo la x inicial: xenofobia, xilófono, etc., QUE PASA CON ESTO ??
	text = strsubn(text, "x", "ʃ") --> DIFERENCIA FUNDAMENTAL: cómo mapear la x

	--c, g, q
	text = strsubb(text, "c([ie])",  "θ"  .. "%1") -- Busco si hay ceceos y los sustituyo. ¿Por qué habían puesto la z?
	text = strsubn(text, "g([iey])", "x%1") -- must happen after handling of x above
	text = strsubn(text, "gu([ie])", "g%1")
	text = strsubn(text, "gü([ie])", "gu%1")
	text = strsubn(text, "ng([^aeiouüwhlr#])", "n%1") -- [[Bangkok]], [[ángstrom]], [[electroswing]], no aplica para [[branding]] (hay que acentuarla manualmente)
	text = strsubn(text, "qu([ie])", "k%1")
	text = strsubn(text, "ü", "u") -- [[Düsseldorf]], [[hübnerita]], obsolete [[freqüentemente]], etc.
	text = strsubn(text, "q", "k") -- [[quark]], [[Qatar]], [[burqa]], [[Iraq]], etc.

	-- map various consonants to their phoneme equivalent
	text = strsubn(text, "[cjñrv]", {["c"]="k", ["j"]="x", ["ñ"]="ɲ", ["r"]="ɾ", ["v"]="b" })

	-- ([[hielo]], [[enhiesto]], [[deshielo]], ...)
	local word_initial_hi, syl_initial_hi, initial_hi
	text, word_initial_hi = strsubb(text, "#h?[iy](" .. VOCAL .. ")", "#ʝ%1") -- [[hiena]], [[hieráticu]], diferencia con el español ?
	text, syl_initial_hi = strsubb(text, "(" .. CONS .. SEPARADORES_SILABICOS .. "*)h[iy](" .. VOCAL .. ")", "%1j%2")
	initial_hi = word_initial_hi or syl_initial_hi
	--  ([[huevo]], [[deshuesar]])
	text = strsubb(text, "(" .. CONS_O_SEP_PALABRA .. SEPARADORES_SILABICOS .. "*)hu(" .. VOCAL .. ")", "%1" .. TEMP_W .. "%2")

	
	-- ll
	text = strsubn(text, "ll#", "l#") -- [[krill]]
	text = strsubn(text, "ll", "ʎ")

	--Sustituyo rr y lr por r ¿no falta buscar el separador silábico en lr y sr?
	text = strsubn(text, "ɾɾ", "r")
	text = strsubn(text, "([#lnsθ])ɾ", "%1r") --([[alrededor]], [[malrotar]]), nr ([[enriquecer]], [[sonrisa]], etc.), sr ([[Israel]], [[desregular]], etc.), zr ([[Azrael]], [[cruzrojista]]), rr
	text = strsubn(text, "nn", "N") --doble n (ennoblecer) ¿por qué una N grande en lugar de meter un separador silábico?
	text = strsubn(text, "bb", "B") --doble b (subbase) ¿por qué una B grande en lugar de meter un separador silábico?

	text = strsubn(text, "(" .. CONS .. ")%1", "%1") -- elimino consonantes dobles [[Addis Abeba]], [[cappa]], [[descender]], [[crackear]]
	text = strsubn(text, "sθ", "θ") -- elimino sz como en [[fascinante]]

	-- restablezco las consonantes dobles, MUY OSCURO ESTO
	text = strsubn(text, "N", "nn")
	text = strsubn(text, "B", "bb")

	--sustitución de oclusivas (T) cuando se juntan con ptk --> esta parte no tiene sentido
	--local voice_stop = { ["p"] = "b", ["t"] = "d", ["k"] = "g" }
	--text = strsubn(text, "t(" .. SEPARADOR .. "*[sθ])", "!%1") -- eximir -ts-, -tz-
	--text = strsubn(text, "([ptk])(" .. SEPARADOR .. "*" .. T .. ")", function(stop, after) return voice_stop[stop] .. after end)
	--text = strsubn(text, "!", "t") -- recuperar -ts-, -tz-

	text = strsubn(text, "n([# .]*[bpm])", "m%1") --nb, bp, nm por mb, mp, mm (ejemplo: enviar, inmoral, etc.)

	text = strsubn(text, "h", "") --sacar la h muda

	-- i and u between vowels -> consonant-like substitutions: [[paranoia]], [[baiano]], [[abreuense]], [[alauita]],
	-- [[Malaui]], etc.; also with h, as in [[marihuana]], [[parihuela]], [[antihielo]], [[pelluhuano]], [[náhuatl]],
	-- etc. Add .* at the beginning so we go right-to-left, in the case of [[hawaiiano]] -> ha.wai.iano.
	text = strsubrep(text, "(.*" .. VOCAL .. DIACRITICO .. "*h?)([iu])(" .. VOCAL .. ")",
		function (v1, iu, v2) return v1 .. vowel_to_glide[iu] .. v2 end
	)
	
	-- switch -> swich
	text = strsubn(text, "t".."("..SEPARADORES_SILABICOS.."?"..comodin_chancho..")", "%1")
	
	words = strsplit(text, "[#(%s)]+")
	local ac_words = {}
	for _,word in ipairs(words) do
		if #word > 0 then
			if strfind(word, "|") then
				insert(ac_words, word)
			else
				insert(ac_words, reemplazar_tildes(separar_en_silabas_final(word)))
			end
		end
	end
	
	text = concat(ac_words, " ")
	text = strsubn(text, " | ", "# | #")
	text = "##" .. strsubn(text, " ", "# #") .. "##"

	--diphthongs; do not include TEMP_Y here
	text = strsubn(text, "u"..comodin_yeista.."iɾ", "wir") -- el -uyir antihiático
	text = strsubn(text, "i([aeou])", "j%1")
	text = strsubn(text, "u([aeo])", "w%1")
	text = strsubn(text, "ui", "uj") -- caso aparte que no se da en el español
	text = strsubn(text, "([aeiou])y", "%1j")
	--text = strsubn(text, TEMP_Y, "i") -- -ay/-ey/-oy/-uy
	text = strsubn(text, "([aeiou])i#", "%1j#") -- -ai/-ei/-oi/-ui
	text = strsubn(text, "i i#", "ij#")
	
	-- simplifico vocales dobles (propio del asturiano)
	text = strsubn(text, "("..VOCAL..")%1", "%1")
	
	-- z
	text = strsubb(text, "z", "θ")

	-- suppress syllable mark before IPA stress indicator
	text = strsubn(text, "%.(" .. ACENTOS_IPA .. ")", "%1")
	--make all primary stresses but the last one be secondary
	text = strsubrep(text, ac_primario.."(.+)"..ac_primario, ac_secundario.."%1"..ac_primario)
	
	-- g
	text = strsubn(text, "g", "ɣ")
	
	-- grafías dialectales
	text = strsubn(text, "ḷḷ", "ʈ͡ʂ")
	text = strsubn(text, "ḥ", "h")

	--phonetic transcription --> más fino, lo que se escribe entre [] corchetes
	if phonetic then
		local voiced = "mnɲbd"..comodin_yeista.."gʎ" .. TEMP_W
		local r_cluster = "ɾr"
		local tovoiced = {
			["θ"] = "θ̬",
			--["s"] = "z",
			--["f"] = "v",
		}
		local function voice(sound, following)
			return tovoiced[sound] .. following
		end

		-- aproximantes: convierto 
		local stop_to_fricative = {["b"] = "β", ["d"] = "ð"}
		local fricative_to_stop = {["β"] = "b", ["ð"] = "d"}
		text = strsubn(text, "[bd]", stop_to_fricative) --convierto todo a fricativa
		
		-- Excepciones a fricativas: consonante inicial, luego de m, n y luego de l-m-n(g) para la d
		text = strsubn(text, "([mnɲ]" .. SEPARADOR .. "*)([β])", --salvo las precedidas por m,n,ng (convierto de nuevo)
			function(nasal, fricative) return nasal .. fricative_to_stop[fricative] end
		)
		text = strsubn(text, "([lʎmnɲ]" .. SEPARADOR .. "*)([ð])",  --salvo las precedidas por lm,ln,lng, (convierto de nuevo)
			function(nasal_l, fricative) return nasal_l .. fricative_to_stop[fricative] end
		)
		text = strsubn(text, "(##" .. ACENTOS_IPA .. "*)([βð])", --salvo las sílabas iniciales (convierto de nuevo)
			function(stress, fricative) return stress .. fricative_to_stop[fricative] end
		)
		
		text = strsubn(text, "([ae])k("..SEPARADOR..")θ", "%1i%2θ") -- [[redacción]] ~ «redaición» (acc/ecc -> aic/eic)
		text = strsubn(text, "([ae])k("..SEPARADOR..")t", "%1u%2t") -- [[redactor]] ~ «redautor» (act/ect -> aut/eut)
		text = strsubn(text, "[βðkɣp]("..SEPARADOR..")([^"..vocales.."βðkɣp".."])", "%2%1%2") -- geminación para consonantes al final de silaba: absolutu -> assolutu
		text = strsubn(text, "n#", "ŋ#") -- velarización de la n final
		
		text = strsubn(text, "[td]", {["t"] = "t̪", ["d"] = "d̪"}) --dentalización

		text = strsubn(text, "([θ])(" .. SEPARADOR .. "*[" .. voiced .. r_cluster .. "])", voice)

		-- nasal assimilation before consonants
		local labiodental, dentialveolar, dental, alveolopalatal, palatal, velar =	"ɱ", "n̪", "n̟", "nʲ", "ɲ", "ŋ"
		local nasal_assimilation = {
			["f"] = labiodental,
			["t"] = dentialveolar, ["d"] = dentialveolar,
			["θ"] = dental,
			[comodin_chancho] = alveolopalatal,	["ʃ"] = alveolopalatal,	["ʒ"] = alveolopalatal,
			[comodin_yeista] = palatal, ["ʎ"] = palatal,
			["k"] = velar, ["x"] = velar, ["g"] = velar,
		}
		text = strsubn(text, "n(" .. SEPARADOR .. "*)(.)", function(stress, following) return (nasal_assimilation[following] or "n") .. stress .. following end)

		-- lateral assimilation before consonants
		text = strsubn(text, "l(" .. SEPARADOR .. "*)(.)",
			function(stress, following)
				local l = "l"
				if following == "t" or following == "d" then -- dentialveolar
					l = "l̪"
				elseif following == "θ" then -- dental
					l = "l̟"
				elseif following == comodin_chancho or following == "ʃ" then -- alveolopalatal
					l = "lʲ"
				end
				return l .. stress .. following
			end)

		--semivowels
		text = strsubn(text, "([aeouãẽõũ][iĩ])", "%1̯")
		text = strsubn(text, "([aeioãẽĩõ][uũ])", "%1̯")

		-- voiced fricatives are actually approximants
		text = strsubn(text, "([βðɣ])", "%1̞")
	end

	-- final conversions
	text = strsubn(text, COMODINES, recuperar_comodin)
	text = strsubn(text, divsil, ".")
	text = strnfc(text)
	
	return {{"pronunciación"}}, {{text}}
end

-- Punto de entrada externo, recibe el título de página y los argumentos de plantilla
function export.procesar_pron_args(titulo, args)
	local tit = titulo
	local vino_ayuda, ss_
	
	if #args["ayuda"] < 1 then
		args["ayuda"][1] = tit
	else
		vino_ayuda = true
	end

	if #args["fone"] < 1 and #args["fono"] < 1 then
		if #titulo == 1 then
			if titulo >= "a" and titulo <= "z" then
				args["ayuda"] = pron_abc[string.byte(titulo) - 96]
				args["tl"] = args["ayuda"]
			elseif titulo >= "A" and titulo <= "Z" then
				args["ayuda"] = pron_abc[string.byte(titulo) - 64]
				args["tl"] = args["ayuda"]
			end
		elseif titulo == "ñ" or titulo == "Ñ" then
			args["ayuda"] = pron_abc[27]
			args["tl"] = args["ayuda"]
		end
		local A = #args["ayuda"]
		local j = 1 -- indice de la ayuda
		local k = 1 -- cantidad de pronunciaciones insertadas (máximo 9)
		while k <= 9 and j <= A do
			local pron, fone = generar_pron(args["ayuda"][j], true)
			for i,_ in ipairs(pron) do
				insert(args["pron"], pron[i])
				insert(args["fone"], fone[i])
				k = k + 1
				if k > 9 then
					break
				end
			end
			j = j + 1
		end
	end
	
	if not strfind(args["ayuda"][1], VOCAL_GENERAL) then
		return args	
	end
	
	if not args["rima"][1] then
		local palabras = strsplit(args["ayuda"][1], "%s+")
		local rims = {}
		local _, fono = generar_pron(palabras[#palabras], false)
		for _,f in ipairs(fono) do
			local rim = f[1]
			rim = strsub(rim, "^.*"..ac_primario.."(.-)$", "%1")
			rim = strsub(rim, ".-".."("..VOCAL_GENERAL..".*"..")".."$", "%1")
			if rim and rim ~= "" then
				rims[rim] = true
			end
		end
		for rim,v in pairs(rims) do
			insert(args["rima"], rim)
		end
	end
	
	if strfind(args["ayuda"][1], "%s") then
		return args
	end
	
	if #args["d"] < 1 and #titulo > 1 and titulo ~= "ñ" and titulo ~= "Ñ" then
		if not args["ls"][1] and not args["ac"][1] and #titulo > 1 then
			local ls = {}
			local ac = {}
			for _,a in ipairs(args["ayuda"]) do
				ss_ = separar_en_silabas(a)
				local lon, ace = obtener_informacion(ss_)
				ls[lon] = true
				ac[ace] = true
			end
			for lon,_ in pairs(ls) do
				insert(args["ls"], lon)
			end
			for ace,_ in pairs(ac) do
				insert(args["ac"], ace)
			end
		end
		
		-- obtenida la “información” de la palabra en base a la “ayuda”, determino cómo mostrar la grafía original
		if not vino_ayuda then -- situación normal
			args["d"][1] = separar_en_silabas(args["ayuda"][1]) -- división en sílabas
		else -- palabra extranjera, vino con ayuda --> veo cómo quedaría mejor
			local tit_sombra = quitar_diacriticos(tit)
			local ss_ayuda = quitar_diacriticos(ss_)
			local ss = tit
			local j0 = 0 -- desde dónde debería buscar la próxima coincidencia de letras
			
			while true do
				local i = strfind(ss_ayuda, "[a-zA-ZÀ-ž]%-[a-zA-ZÀ-ž]")
				if not i or i < 1 then
					break
				end
				local a, b = substr(ss_ayuda, i, i), substr(ss_ayuda, i+2, i+2)
				local ab = a..b 
				local j = strfind(tit_sombra, ab, j0) -- veo si encuentro la separación
				if j then -- Si aparece en el título, entonces inserto separador ahí miemo
					tit_sombra = substr(tit_sombra, 1, j).."-"..substr(tit_sombra, j+1)
					ss = substr(ss, 1, j).."-"..substr(ss, j+1)
					j0 = j+2 -- incremento dos: por la primera letra y por el guion
				else --Sino, veo si al menos coincide con una de las dos letras
					local k = strfind(tit_sombra, a, j0) or math.huge
					local l = strfind(tit_sombra, b, j0) or math.huge
					if k < l and k >= 1 then
						tit_sombra = substr(tit_sombra, 1, k).."-"..substr(tit_sombra, k+1)
						ss = substr(ss, 1, k).."-"..substr(ss, k+1)
						j0 = k+2
					elseif l < k and l >= 2 then
						tit_sombra = substr(tit_sombra, 1, l-1).."-"..substr(tit_sombra, l)
						ss = substr(ss, 1, l-1).."-"..substr(ss, l)
						j0 = l+1 -- en este caso se agrega sólo el guion porque la letra considerada es la segunda
					end
				end
				ss_ayuda = substr(ss_ayuda, i+2) -- trunco la ayuda para obtener la siguiente separación
			end
			
			--junto sílabas que sólo tengan consonantes
			ss = "-"..ss.."-"
			ss = strsubrep(ss, "("..SEPARADORES_SILABICOS..CONS.."+)"..SEPARADORES_SILABICOS.."("..SALVO_SEPARADORES_SILABICOS.."-"..VOCAL_GENERAL..")", "%1%2")
			ss = strsubrep(ss, "("..SEPARADORES_SILABICOS..SALVO_SEPARADORES_SILABICOS.."-)"..SEPARADORES_SILABICOS.."("..CONS.."+"..SEPARADORES_SILABICOS..")", "%1%2")
			
			-- limpio los separadores de más
			ss = strsubn(ss, SEPARADORES_SILABICOS .. "+", "-")
			ss = strstrip(ss, SEPARADOR)
			
			args["d"][1] = ss
		end
	end
	
	return args
end

return export