En primer lugar estudié un poco más en detalle el algoritmo de separación en sílabas y encontré esta interesante tesis: Documento sobre separación de palabras en sílabas
Básicamente me interesó la primera propiedad de las sílabas, y es que en cada sílaba tiene que existir al menos una vocal... Esa fue la puerta de entrada, porque si sumo los triptongos (y los quito de la palabra) y lo mismo hago con los diptongos, y eventualmente con los diptongos poéticos, me basta sumar e eso la cantidad de vocales que encuentro en la palabra resultante y obtengo la cantidad de sílabas.
Veamos un ejemplo:
Para la palabra concierto:
regla | palabra Inicial | encontrados | palabra resultante | cantidad de sílabas |
triptongos | concierto | -- | concierto | 0 |
diptongos | conciertos | ie (1) | concrto | 1 |
sinalefas | concrto | -- | concrto | 1 |
vocales | concrto | o-o (2) | cncrt | 3 |
Como vemos, obtuvimos 3 sílabas (y de hecho la palabra se divide en sílabas como con-cier-to)
Ahora queda solo definir qué es un triptongo y qué es un diptongo (y una sinalefa), y el algoritmo estaría completo.
Para quien conoce las expresiones regulares esta parte va a resultar banal, pero no todos los programadores las usan así que un poquito de repaso (solo lo indispensable para entender el algoritmo) no viene mal... Para eso voy a usar la definición de sinalefa ya que es la más simple y contiene los elementos básicos para entender los diptongos y triptongos.
está definido $sinalefa como la unión de las cadenas $vocalNoAcentuada y $vocalAbierta, con lo que resultaría lo siguiente:
$sinalefa = /[aeiou][aeoáéíóú]/i
Que se lee de la siguiente manera: sin importar si es en mayúsculas o minúsculas (por eso está todo encerrado entre las barras con la letra "i") -> /....../i, reconocé todos los grupos de dos vocales que empiecen con cualquier vocal no acentuada y estén seguidas por vocales abiertas (a,e,o) o vocales acentuadas.
En resúmen, los siguientes grupos (pero hay otros más) serán reconocidos como sinalefas: aé-Aé-aÉ-AÉ o ae-Ae-aE-AE (como en aéreo), oe-Oe-oE-OE (como en poeta), etc.
Dejo a ustedes el estudio (si les interesa) de las otras opciones, les baste saber que más de un patrón separado por barra vertical (|) es una opción "o" (or).
Este es el código:
static function calculaSilabas($palabra,$poética="no") {
$vocales = '[aeiouáéíóú]';
$vocalAbierta = '[aeoáéíóú]';
$vocalNoAcentuada = '[aeiou]';
$vocalCerrada = '[ui]';
$yComoVocal = 'y';
$noVocales = "[^aeiouáéíóú]";
$triptongos = "/$vocalAbierta$vocalCerrada$vocalCerrada|$vocalCerrada$vocalCerrada$vocalAbierta/i";
$diptongos = "/$vocalAbierta$vocalCerrada|$vocalCerrada$vocalAbierta|$vocalCerrada$vocalCerrada|$vocales$yComoVocal$noVocales|$vocales$yComoVocal$/i";
$sinalefa = "/$vocalNoAcentuada$vocalAbierta/i"; // se va la primera !!!!
$cantidadSinalefas = 0;
$palabra = preg_replace($triptongos,'', $palabra, -1 , $cantidadTriptongos);
$palabra = preg_replace($diptongos,'', $palabra, -1 , $cantidadDiptongos);
if ($poética<>"no") {
$palabra = preg_replace($sinalefa,'', $palabra, -1 , $cantidadSinalefas);
}
$palabra = preg_replace("/$vocales/i",'', $palabra, -1 , $cantidadVocales);
$silabas = $cantidadTriptongos+$cantidadDiptongos+$cantidadSinalefas+$cantidadVocales;
return $silabas;
}