A practicar

A practicar con recursividad

A practicar Desarrollo

Aquí está la serie A practicar… donde buscamos poner en práctica lo que vamos aprendiendo. En esta ocasión vamos a practicar con recursividad después de haber visto las funciones recursivas y los problemas encontrados en la ordenación y búsqueda. Así pues, para practicar con recursividad aplicaremos conceptos vistos en esos artículos y todo lo anterior.

Sin embargo, antes de practicar con recursividad debemos resolver el reto del artículo anterior.

Solución al reto anterior

Queríamos realizar un pequeño programa que hiciera uso de una función para validar un nombre. Esta función queríamos que comprobara si el nombre estaba vacío, si cada una de las palabras introducidas empezaba con mayúscula y si tenía caracteres no permitidos. Vamos, primero, a ver la función y luego vamos explicándola:

<?php

function validarNombre($nombreCompleto, $errores = []) {
	// Sanitización del nombre
	$nombreCompleto = trim(htmlspecialchars(strip_tags($nombreCompleto)));

	if (empty($nombreCompleto)) {
		$errores[] = 'No se ha introducido ningún nombre';
	} else {
		$nombreSeparado = explode(' ', $nombreCompleto);
		foreach ($nombreSeparado as $palabra) {
			if (!ctype_upper($palabra[0])) {
				$errores[] = 'La palabra ' . $palabra . ' no empieza por mayúsculas';
			}

			if (!preg_match('/^[a-zA-Z áéíóúüñÑÁÉÍÓÚÜ]+$/i', $palabra)) {
				$errores[] = 'La palabra ' . $palabra . ' tiene caracteres no permitidos';
			}
		}
	}

	return $errores;
}
?>

Sanitización del nombre

En primer lugar vemos que nuestra función validarNombre tiene dos parámetros. Por un lado, recibirá el nombre completo que queremos validar, que no dejará de ser un string introducido por el usuario. En segundo lugar recibe un array que utilizaremos para los errores y que predefinimos como vacío. No vamos a enviar ahora ningún array ya iniciado con errores, pero si tuviéramos más validaciones (de email, por ejmplo, u otros campos) podríamos ir pasando este array e ir incorporando todos los errores.

Para sanitizar hemos usado strip_tags, que va a eliminar las etiquetas HTML y PHP que se puedan introducir, htmlspecialchars para convertir caracteres especiales en entidades HTML y trim para eliminar espacios en blanco que pudieran haber antes y después del nombre y que no nos van a interesar. Tenemos así un string más “limpio” con estas funciones y que eliminará algunos elementos indeseados e innecesarios.

Comprobar que se ha introducido nombre

La siguiente comprobación es sencilla. Necesitamos saber que $nombreCompleto no está vacío, pues indicamos en el enunciado del reto que no íbamos a poner el atributo required en el <input> del formulario. Aunque lo coloquemos, siempre es bueno hacer esta comprobación. Simplemente utilizando la función predefinida empty que nos sería para validar, entre otras cosas, vemos si el nombre no es una cadena vacía. Si lo fuera, añadiríamos el mensaje de error a nuestro array de errores.

Comprobar que cada palabra empieza por mayúscula

Hemos querido indicar que cada palabra del nombre tiene que comenzar con una mayúscula. Aunque sería fácil utilizar una de las funciones predefinidas de PHP como es ucfirst y que transforma la primera letra del string pasado a mayúsculas, preferimos que sea el usuario el que lo haga bien.

Para hacer esta comprobación, primero separamos el nombre en todas sus palabras. Para ello utilizamos la función explode, que va a dividir nuestro nombre en un array de palabras porque le estamos indicando que el campo de división es un espacio en blanco (cuidado, no la cadena vacía).

A continuación, se recorren todas las palabras del nombre, pues ahora las tenemos en un array en las que cada elemento es una de las palabras, y procedemos a la comprobación. Para comprobar si la primera letra de una palabra está en mayúsculas se utiliza la función ctype_upper en, atención, la primera letra de la palabra, es decir, en $palabra[0]. Si lo hubiéramos hecho de toda la palabra, intentaría comprobar si todas las letras están en mayúsculas, y no es eso lo que queremos. Por tanto, accedemos al primer elemento pues ya sabemos que un string es un array, e indicamos el error si encontramos una palabra que no empieza por mayúsculas.

Comprobar si existen caracteres no permitidos

Nuestra última comprobación será la de que toda la palabra tenga letras permitidas, incluidas con acentos. Para ello utilizamos preg_match para comprobar si la palabra encaja en el patrón indicado. En dicho patrón estamos diciéndole que sólo están permitidas palabras de la a a la z, de la A a la Z, y luego todas las vocales acentuadas tanto en mayúsculas como en minúsculas, además de la eñe. Esta función la podéis adaptar al idioma que queráis para permitir, por ejemplo, caracteres de tipo ö que no existen en el idioma español o acentos abiertos à para idiomas que los permiten. Si hubiera algún carácter no permitido, lo indicaríamos en el array de errores.

El formulario y su comprobación

<?php

function validarNombre($nombreCompleto, $errores = []) {
	// Sanitización del nombre
	$nombreCompleto = trim(htmlspecialchars(strip_tags($nombreCompleto)));

	if (empty($nombreCompleto)) {
		$errores[] = 'No se ha introducido ningún nombre';
	} else {
		$nombreSeparado = explode(' ', $nombreCompleto);
		foreach ($nombreSeparado as $palabra) {
			if (!ctype_upper($palabra[0])) {
				$errores[] = 'La palabra ' . $palabra . ' no empieza por mayúsculas';
			}

			if (!preg_match('/^[a-zA-Z áéíóúüñÑÁÉÍÓÚÜ]+$/i', $palabra)) {
				$errores[] = 'La palabra ' . $palabra . ' tiene caracteres no permitidos';
			}
		}
	}

	return $errores;
}

if (isset($_POST['formulario'])) {
	$errores = validarNombre($_POST['nombre']);

	if (!empty($errores)) {
		foreach ($errores as $error) {
			echo $error . '<br>';
		}
	} else {
		echo 'Nombre válido';
	}
}
?>

<form action="ejercicio.php" method="post">
	Nombre: <input type="text" name="nombre">

	<input type="submit" name="formulario" value="Enviar">
</form>
?>

Hemos añadido un trozo de código en PHP y el formulario en HTML. Empecemos por el final, por el formulario, pues es sencillo.

El formulario es muy sencillo, pues llama al mismo archivo en el que estamos (al que hemos llamado ejercicio.php) mediante el método post y pide únicamente un campo de tipo texto al que hemos llamado nombre. Posteriormente tenemos un <input> de tipo submit que enviará el formulario y al que hemos nombrado formulario para saber luego cuándo se ha pulsado.

Comprobación general

Al enviar el formulario pasamos a ejecutar de nuevo el mismo archivo y, al llegar a la línea if (isset($_POST[‘formulario’])) { estamos comprobando, simplemente, que el formulario haya sido enviado. Si se ha enviado, esta variable $_POST habrá sido creada. Por tanto, pasaremos a llamar a la función validarNombre que ya teníamos definida pasándole como argumento el nombre que el usuario indicado y que estará en $_POST[‘nombre’]. No le pasamos el array de errores porque no existe todavía y ya se encargará de crearlo la función con ese parámetro predefinido.

Esta función, como ya hemos visto, nos devolverá un array de errores. Si este array está vacío, entonces el nombre es válido y simplemente lo imprimimos por pantalla. Pero si no está vacío es porque ha encontrado alguno de los errores que hemos descrito anteriormente. Por tanto, lo recorreremos e iremos imprimiendo los mensajes de error acumulados.

Probando nuestro programa

Vamos a hacer unas cuantas pruebas. Si enviamos el formulario sin haber escrito nada en el campo nombre, obtenemos lo siguiente:

No se ha introducido ningún nombre

Bien, esta parte funciona correctamente. Si ahora enviamos el formulario escribiendo el string prueb@ De Mu1|ip1€$ errores veremos por pantalla estos mensajes:

La palabra prueb@ no empieza por mayúsculas
La palabra prueb@ tiene caracteres no permitidos
La palabra Mu1|ip1€$ tiene caracteres no permitidos
La palabra errores no empieza por mayúsculas

Vemos que está funcionando bien. La palabra prueb@ nos indica que no empieza por mayúsculas y, además, tiene caracteres no permitidos con esa @ que hemos colocado por ahí. No se ha quejado, como esperábamos, de la palabra De, pues todo es correcto en ella. De nuevo indica que Mu1|ip1€$ tiene caracteres no permitidos, aunque como veis no indica que no empiece por mayúscula, pues esto está bien. Sí indicará que no empieza con mayúsculas la palabra errores, así que por lo visto, todo funciona como esperábamos.

Vamos ahora a poner Sergio Pérez Muñoz, por ejemplo:

Nombre válido

Genial, lo tenemos. Ha comprobado que todas las letras empiezan por mayúscula y que todo tiene letras permitidas, incluido ese acento y esa eñe que hay en el nombre. Tenemos, pues, una función que ha comprobado y validado un nombre en base a aspectos definidos por nosotros mismos. De esta forma sabemos que ningún usuario podrá indicar cosas raras, al menos en cuanto a caracteres, en este campo.

Siguiente reto

Vamos a practicar con ordenación recursiva en un nuevo reto que va a ser conceptualmente el más complejo al que nos hemos enfrentado ahora, especialmente porque practicar con recursividad requiere un buen planteamiento del problema.

A practicar 2.1.1

Tenemos el array indicado justo después de este recuadro azul, en el cual vemos que se trata de un array con números en su interior pero también arrays con más números en su interior con varias dimensiones, es decir, que pueden tener dentro todos los arrays con números que queramos.

Se deben crear dos funciones recursivas. La primera de ellas la vamos a nombrar suma_recursiva, la cual recibirá este array y sumará todos sus valores para darnos la suma total, todo ello realizándolo de manera recursiva, por supuesto.

La segunda función, reorganizar_recursivamente, va a tener dos parámetros. Uno será el array el segundo será el que llamaremos $nuevoArray y que, por defecto, será un array vacío. Esta función va a reorganizar el array de tal forma que recorra los valores y los vaya sumando. En el momento en que encuentre un valor que sea un array, creará un nuevo elemento en $nuevoArray con la suma que llevaba hasta ahora, pondrá la suma a 0 y sumará los siguientes números del nuevo array. Esto debe hacerlo recursivamente hasta llegar a un nuevo array que contendrá las sumas que se han ido realizando, pues recordemos que estamos buscando practicar con recursividad.

Pista: en total aparecerán 11 elementos en $nuevoArray.

<?php
$array = array(
	6,
	5,
	2,
	array(
		5,
		2,
		8,
		7,
		5,
		array(
			6,
			3,
			7,
			8,
			1
		),
		3
	),
	8,
	6,
	array(
		7,
		1,
		array(
			8,
			3,
			2,
			array(
				5,
				2,
				3,
				9,
				1
			),
			7,
			6,
			5,
			4
		),
		2,
		8,
		1,
		8,
		7
	),
	1,
	2,
	6,
	9
);
?>

Como veis, es un reto más complejo el tener que practicar con recursividad, especialmente la segunda parte, pues requiere pensar bien qué estamos haciendo. Deberéis usar algunas funciones para arrays y saber bien cuándo utilizar la recursividad. La solución, en dos semanas.

Deja una respuesta