Comunidad de diseño web y desarrollo en internet

Formato Tipo Título a textos con PHP respetando acentos

Hola a todos! en este tutorial veremos cómo dar a un texto cualquiera el formato para que aparezca en Tipo Título en PHP.

Bueno para empezar primero definamos de manera concisa que es “Tipo Título”. En un texto tipo título todas las primeras letras, sin importar el tipo de palabra, (sea preposición, artículo, verbo …), aparece en mayúscula.

Ejemplo:

Hola Esta Es Una Oración En Tipo Título.


Aparentemente es fácil este problema para un programador en PHP en nivel medio-avanzado. En PHP existen dos funciones que podrían intuitivamente ser utilizadas para resolver el problema.

La función strtolower (Convierte una cadena a minúsculas), esta función retorna un string con todo el contenido en minúsculas. Se utiliza de la siguiente forma $retorno = strtolower($string); donde $string debe ser de tipo string.

La otra función que mencionaba que puede ser adecuada para resolver este problema es la función ucwords (Convierte a mayúsculas el primer carácter de cada palabra en una cadena), esta función retorna un string con todo las primeras letras de una palabra en mayúsculas. Se utiliza muy similar a strtolower $retorno = ucwords($string); donde $string debe ser de tipo string.

Para los programadores despistados que no han deducido hasta el momento como utilizar estas dos funciones para resolver el problema, la solución sería así:

Código :

<?php
ucwords(strtolower($texto1));
?>
En donde $texto1 es la variable en la cuál guardamos nuestro string.

Aparentemente, no existe ningún problema con la mezcla de estas dos funciones si convertimos un texto como el siguiente

Código :

<?php
$texto = "este TEXTO ES Fácil de convertir a tipo título";
print ucwords(strtolower($texto3)); //Salida: Este Texto Es Fácil De Convertir A Tipo Título
?>
Pero la realidad es otra la cual la expondré con un código más elaborado

Código :

<?php
$texto1 = "ESTE TÍTULO ESTA EN MAYÚSCULAS ÁÉÍÓÚÑ ÁBACO Ñ";
$texto2 = "este título esta en minúsculas áéíóú ábaco ñ";
$texto3 = "este TEXTO ES Fácil de convertir a tipo título";


//Estrategía incorrecta:
//Convertir todo el texto a minúscula y pasar la primera letra de cada palabra a mayúsculas
//Primer Ejemplo Incorrecto:
print ucwords(strtolower($texto1)) . "<br>"; //Salida: Este TÍtulo Esta En MayÚsculas ÁÉÍÓÚÑ Ábaco Ñ

//Segundo Ejemplo Incorrecto:
print ucwords(strtolower($texto2)) . "<br>"; //Salida: Este Título Esta En Minúsculas áéíóú ábaco ñ

//Tercer Ejemplo Correcto;
print ucwords(strtolower($texto3)) . "<br>"; //Salida: Este Texto Es Fácil De Convertir A Tipo Título

?>
Ohh, esto si es mucho más elaborado. Ok, miremos aquí los resultados. Con el uso de

Código :

print ucwords(strtolower($texto1)); 
Podemos observar que existen dos ejemplos que generan una respuesta incorrecta.

En el Primer Ejemplo Incorrecto El texto ingresado estaba totalmente en mayúsculas. Vemos en la salida estas dos peculiaridades: ” MayÚsculas ÁÉÍÓÚ “. Como se puede observar en la primera y la segunda palabra las letras acentuadas aparecen en mayúsculas, aún después de ser devuelta por la función que convierte todo el texto en minúsculas (strtolower)

En el Segundo Ejemplo Incorrecto El texto ingresado estaba totalmente en minúsculas. Vemos en la salida estas tres peculiaridades: ” áéíóú ábaco ñ “. Como se puede observar en la primera, segunda y tercera palabra si las letras acentuadas aparecen al principio de la palabra esta no cambia a mayúscula a pesar de utilizar la función ucwords.

¿Qué podemos deducir sobre este comportamiento? Que tanto la función strtolower como ucwords no generan la respuesta esperada para letras acentuadas.

Yo pensé varias alternativas para solucionar este problema. Mencionare dos de ellas que aparentemente eran buenas:

1. Escapar a entidades HTML las letras acentuadas( y la ñ específicamente). La idea básica es escapar los caracteres para que las funciones ( strtolower y ucwords) puedan actuar de manera adecuada. Pero al pasar una frase como Ábaco ábaco en dicho ejemplo ocurriría algo así:

Código :

<?php
$texto1 = "Ábaco ábaco";
print ucwords(strtolower(htmlentities($texto1))); //Salida: ábaco ábaco
?>
Como se observa, la salida no generó las mayúsculas deseadas, esto básicamente es causado por lo siguiente:

La función htmlentities escapa todos los caracteres “extraños” a entidades html. Para nuestro caso convierte "Ábaco ábaco" en “&Aacute;baco &aacute;baco” luego la función strtolower pasa todo a minúsculas lo cual genera “&aacute;baco &aacute;baco”. Posteriormente la función ucwords pasa las primeras letras a mayúsculas pero si observamos la primera letra de ambos ejemplos es & por lo cual la salida es “&aacute;baco &aacute;baco” Lo cuál genera en el navegador “ábaco ábaco”. Por ende no es una optima solución

2. utilizar la función str_replace y remplazar directamente los caracteres problemáticos. Para dicha idea se debía implementar un código como el siguiente

Código :

<?php
/*
   String: dar formato a tipo título por medio de PHP respetando acentos y ñ usando arrays
   Autor: John Sánchez Alvarez
   Este código es libre de usar y modificarse
*/
$texto1 = "ÁÉÍÓÚ áéíóú MAYÚSCULAS ábaco ñ";
$search = array("Á", "É", "Í", "Ó", "Ú", "á", "é", "í", "ó", "ú", "Ñ", "ñ");
$replace = array("A[a]", "E[a]", "I[a]", "O[a]", "U[a]", "a[a]", "e[a]", "i[a]", "o[a]", "u[a]", "N[a]", "n[a]");

$texto_salida = str_replace($search, $replace, $texto1);
$tipo_titulo = ucwords(strtolower($texto_salida));

print str_replace($replace, $search, $tipo_titulo); // Salida: Áéíóú Áéíóú Mayúsculas Ábaco Ñ
?>
Aprovechando que str_replace soporta la recepción de arrays, podemos hacer un array de busqueda y un array de remplazo pero teniendo en cuenta que los elementos deben estar en una correspondencia biunivoca.

La función str_replace primero remplaza las letras acentuadas por una letra distintiva,, por ejemplo para Á, yo utilicé A[a], así puedo identificar las letras acentuadas sin que estén acentuadas. Después se pasa el resultado a través de las funciones strtolower y ucwords respectivamente, y se vuelve a realizar la función str_replace para restaurar los acentos. Funciona, pero no es la mejor manera.

La mejor solución

Como se pudo observar, la segunda solución que planteo resuelve el problema, aunque no es muy óptima para implementar, ya que debemos generar los array de búsqueda y remplazo manualmente, por ende, si nos queda por fuera algún carácter, este no será correctamente interpretado.

A partir de PHP versión 4.3.0 podemos disponer de una función que suple este pequeño defecto de PHP. La función mb_convert_case la cual recibe tres parámetros, un string, un mode, y una codificación. Su utilización es de la siguiente manera.

Código :

<?php

/*
   String: dar formato a tipo título por medio de PHP respetando acentos y ñ sin uso de expresiones regulares o arrays, php >= 4.3.0
   Autor: John Sánchez Alvarez
   Este código es libre de usar y modificarse
*/

$texto1 = "ESTE TÍTULO ESTA EN MAYÚSCULAS ÁÉÍÓÚÑ ÁBACO Ñ";
$texto2 = "este título esta en minúsculas áéíóú ábaco ñ";
$texto3 = "este TEXTO ES Fácil de convertir a tipo título";

//Estrategía:
//Darle formato tipo titulo utilizando una codificación de caracteres. La codificación a utilizar depende de la codificación usada en el documento
//Primer Ejemplo Correcto 
print mb_convert_case($texto1, MB_CASE_TITLE, "ISO-8859-1") . "<br>"; //Salida: Este Título Esta En Mayúsculas Áéíóúñ Ábaco Ñ

//Segundo Ejemplo Correcto
print mb_convert_case($texto2, MB_CASE_TITLE, "ISO-8859-1") . "<br>"; //Salida: Este Título Esta En Mayúsculas Áéíóúñ Ábaco Ñ

//Tercer Ejemplo Correcto
print mb_convert_case($texto3, MB_CASE_TITLE, "ISO-8859-1") . "<br>"; //Salida: Este Texto Es Fácil De Convertir A Tipo Título?>
Con esta función obtenemos la salida deseada con pocas líneas de código y con pocos efectos secundarios a tener en cuenta.

Explicaré un poco mejor la función mb_convert_case. El primer parámetro es el string al cual deseamos darle formato. El segundo parámetro es el tipo de conversión de formato deseado. Solo existen tres posibilidades MB_CASE_UPPER, MB_CASE_LOWER y MB_CASE_TITLE (Nota: se escriben en mayúsculas). El tercer parámetro es la codificación de caracteres a utilizar las cuales pueden ser ISO-8859-1, ISO-8859-15, UTF-8, Shift_JIS … La cúal se escribe entre comillas.

Cuál es el efecto colateral de esta función. Siempre se deben tener en cuenta dos cosas en el caso del castellano. Primero la codificación del documento, segundo si es necesario codificación o decodificación del string ingresado en utf-8.

En mi caso cuando hice las pruebas, mi editor de php (bluefish) está configurado para codificar automáticamente los documentos creados a ISO-8859-1, por lo cual en la función se utilice dicho juego de caracteres, pero por lo general,como casi siempre se utiliza UTF-8, siempre es importante establecer el juego de caracteres para su correcta utilización.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate