Trabajar con cadenas.

Manipular el contenido de una cadena.

La manipulación de cadenas es muy común en la vida diaria de un desarrollador. El desarrollador necesita realizar tareas como duplicar cadenas, transformarlas en mayúsculas o verificar si algún caracter corresponde a un tipo en especial. Para este tipo de tareas, esta librería dispone de una serie de funciones cuyo uso no dista mucho de las ya desarrolladas en la Libc™.

Duplicación de cadenas.

Si lo que se desea es duplicar cadenas, las funciones g_strdup> y g_strndup resolverán esa necesidad. Las dos funciones realizan el mismo trabajo: duplican la cadena que se le ha pasado como parámetro. La diferencia radica en que la segunda limita el número de caracteres que devuelve a un número que le es indicado por un segundo parámetro de la función.

gchar * g_strdup ( cadena_para_duplicar ); 
const gchar *   cadena_para_duplicar ;
gchar * g_strndup ( cadena_para_duplicar ,  
  longitud_maxima ); 
const gchar *   cadena_para_duplicar ;
gsize   longitud_maxima ;

Verificación de caracteres.

El título se refiere al conjunto de funciones capaces de responder a preguntas como: ¿Este carácter es un dígito? o ¿este carácter es una letra?... Este tipo de funciones es muy usado en el tratamiento de cadenas y su funcionamiento es muy simple. Estas funciones reciben un carácter y devuelven cierto o falso. La siguiente tabla explica cuáles son esas funciones y cuál es la verificación que realizan. Se recomienda la observación del prototipo de la función g_ascii_isalnum, usado como ejemplo para una mejor comprensión de la tabla, ya que todas las funciones comparten el mismo prototipo.

gboolean g_ascii_isalnum ( caracter ); 
gchar   caracter ;

Tabla 5. Funciones de verificación de caracteres.

Nombre de funciónEs cierto si...
g_ascii_isalnumEs un carácter alfanumérico.
g_ascii_isalphaEs un carácter del alfabeto.
g_ascii_iscntrlEs un carácter de control.
g_ascii_isdigitEs un dígito.
g_ascii_isgraphEs un carácter imprimible y no es un espacio.
g_ascii_islowerEs una letra minúscula.
g_ascii_isprintEs un carácter imprimible.
g_ascii_ispunctEs un carácter de puntuación.
g_ascii_isspaceEs un espacio.
g_ascii_isupperEs una letra mayúscula.

Copia y concatenación de cadenas.

Otra acción típica para el programador es la copia de una cadena o la concatenación de de múltiples cadenas. Para realizar esta tarea podemos utilizar la función g_stpcpy. Esta función desempeña la tarea de copiar una cadena que nosotros le pasemos como parámetro a una cadena destino, también pasada como parámetro. Esta función tiene la particularidad de devolver un puntero a la última posición de la cadena destino, de tal modo que, si se quisiera concatenar cadenas, sólo se tendría que pasar el puntero devuelto por el primer g_stpcpy al segundo como si fuera el destino. Así el segundo g_stpcpy entendería que ha de copiar la segunda cadena al final de la primera que hemos copiado anteriormente y así sucesivamente. Siguiendo este método, se podría concatenar una cadena tras otra.

gchar * g_stpcpy ( cadena_destino ,  
  cadena_origen ); 
gchar *   cadena_destino ;
const gchar *   cadena_origen ;

GString : la otra manera de ver una cadena.

GString es un TAD (tipo abstracto de datos) que implementa GLib™. Este TAD es un buffer de texto que tiene la capacidad de expandirse, realojando memoria automáticamente, sin que el programador tenga que actuar. Esto es realmente útil para el trabajo con cadenas, porque cuando nosotros reservamos memoria para texto y, más adelante, se nos queda pequeña, el programador tiene que tomarse la molestia de reservar más. Por eso GLib™ implementa GString, que facilita enormemente el manejo de cadenas sin necesidad de estar pendientes de su gestión de memoria.

Para empezar a estudiar este TAD, lo primero que tenemos que conocer es la estructura de datos sobre la que esta diseñada y después estudiaremos las funciones que interactúan con esa estructura.

		  struct GString
		  {
		      gchar  *str;
		      gsize len;
		      gsize allocated_len;
		  };
	
1

En este puntero a una cadena de caracteres es donde se almacenará el contenido de la cadena que nosotros especifiquemos. De este modo, si en algún momento se necesita el contenido de la cadena, sólo es necesario acudir a este campo.

2

Este campo hace referencia a la longitud total de la cadena que está alojada en el campo str de la estructura GString. De este modo, si en str está alojada la cadena "hola", el campo len contendrá el número 4.

Ahora ya sabemos cómo es la estructura GString. El siguiente paso será ver las funciones que trabajan sobre GString con el fin de sacarle el mayor partido a este tipo abstracto de datos.

Cómo se aloja una cadena con GString.

Alojar una cadena con GString es extremadamente sencillo e intuitivo. Para ello usaremos la función g_string_new (), que tiene la forma:

GString * g_string_new ( cadena_inicial ); 
const gchar *   cadena_inicial ;

Esta función recibe como parámetro una cadena y devuelve la estructura GString. De este modo, dentro de la estructura GString, tendremos toda la información y, si el lector se ha percatado, en la creación de la cadena, nosotros no hemos tenido que realizar ningún movimiento para alojar memoria.

Ejemplo 6. Crear una cadena con GString.

/* ejemplo del uso de g_string_new */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("!Qué fácil es hacer una cadena!");
        
        g_print ("la cadena que hemos alojado : %s\n", cadena->str);
        g_print ("la longitud de la cadena es : %d\n", cadena->len);
}
	  

Como se puede ver en la ejecución de este ejemplo, la creación de una cadena con GString es muy sencilla. Pero, además, GLib™ nos proporciona otra función para crear cadenas. La sinopsis de esta función es:

GString * g_string_new_len ( cadena_inicial ,  
  longitud_inicial ); 
const gchar *   cadena_inicial ;
gssize   longitud_inicial ;

La ventaja que tiene el uso de g_string_new_len es que nos permite especificar una longitud inicial y esto trae consigo que la cadena que introducimos no tiene necesariamente que estar terminada con el caracter NULL ("\0") y, además, puede tener varios caracteres NULL embebidos dentro de la cadena en cuestión.

Cómo puedo liberar un GString

Siendo GString una estructura, lo suyo sería liberar uno a uno todos los campos pero, gracias a la implementación que nos ofrece GLib™, disponemos de una función que nos ayuda con la liberación de memoria que hemos reservado con la creación de un GString. La sinopsis de esta función sería:

gchar * g_string_free ( cadena ,  
  liberar_contenido_cadena ); 
GString *   cadena ;
gboolean   liberar_contenido_cadena ;

Con la función g_string_free, nosotros podremos liberar el GString que le pasemos como primer argumento a la función. Además, esta función también nos da la posibilidad de liberar o no la cadena que estaría dentro de GString. Y esto se conseguiría si como segundo parámetro le pasásemos el booleano TRUE. En caso contrario, si pasásemos un booleano FALSE, la cadena de caracteres no sería liberada.

Añadir, insertar y borrar cadenas en un GString.

Con los conocimientos necesarios para crear y liberar este tipo de datos, ha llegado el momento de aprender a trabajar con la funciones que tratan la información que aloja y, para empezar, vamos aprender como se puede añadir texto a una cadena creada como GString. A la hora de añadir texto, nos puede interesar añadir texto al final o al principio de la cadena y podemos hacerlo con GString. Las funciones que pasaremos a ver ahora son exactamente iguales, salvo que contienen las palabras append o prepend, que indican que la función añade el texto al final o al principio respectivamente.

GString * g_string_append ( cadena ,  
  cadena_para_añadir_al_final ); 
GString *   cadena ;
gchar *   cadena_para_añadir_al_final ;
GString * g_string_prepend ( cadena ,  
  cadena_para_añadir_al_principio ); 
GString *   cadena ;
gchar *   cadena_para_añadir_al_principio ;

Estas son las primeras funciones para el añadido de texto que vamos a ver. La primera, g_string_append, se encargará de añadir el texto pasado como parámetro al final de la cadena contenida dentro del GString y la segunda, g_string_prepend, se encargara de añadir el texto al principio.

Con el siguiente ejemplo, el lector entenderá el uso práctico de estas funciones.

Ejemplo 7. Añadir cadena a un GString.

/* ejemplo del uso de g_string_append y g_string_prepend */
#include <glib.h>

main (){

        GString *cadena ;
        
        cadena = g_string_new ("*");
        cadena = g_string_append (cadena, "| texto añadido al final");
        cadena = g_string_prepend (cadena, "texto añadido al principio |");
        
        g_print ("\n%s\n", cadena->str);
}
	  

Una vez que el programador sabe añadir texto por delante y por detrás de la cadena contenida dentro del GString, el siguiente paso natural sería aprender cómo se pueden introducir datos dentro de las cadenas, es decir, insertar una cadena. Imagíne que tiene un GString con una cadena. Con la función g_string_insert se puede insertar, en la posición elegida, la cadena que desee. Como puede observar, en la sinopsis de la función y en el siguiente ejemplo, Lo único que tiene que hacer es indicar la posición en la que quiere insertar la cadena y la cadena que se insertará.

GString * g_string_insert ( cadena ,  
  posicion ,  
  cadena_para_insertar ); 
GString *   cadena ;
gssize   posicion ;
gchar *   cadena_para_insertar ;

Ejemplo 8. Insertar una cadena a un GString.

/* ejemplo del uso de g_string_insert */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *cadena_para_insertar = "muy muy ";
        
        cadena = g_string_new ("El día esta soleado");
        cadena = g_string_insert (cadena, 13, cadena_para_insertar);
        
        g_print ("\n%s\n", cadena->str);
        
        g_string_free (cadena, TRUE);
        
}
	  

Con las funciones mostradas anteriormente, podemos añadir información a un GString. Si lo que deseamos es borrar, tenemos la función g_string_erase. Sólo hay que indicar la posición desde la que quiere empezar a borrar y el número de caracteres que desea borrar desde esa posición.

GString * g_string_erase ( cadena ,  
  posicion ,  
  numero_de_caracteres_que_desea_borrar ); 
GString *   cadena ;
gssize   posicion ;
GString *   numero_de_caracteres_que_desea_borrar ;

Ejemplo 9. Borrar una cadena a un GString.

/* ejemplo del uso de g_string_erase */
#include <glib.h>

main (){
        
        GString *cadena ;
        
        cadena = g_string_new ("Esto es una cadena --esto sera borrado--");
        cadena = g_string_erase (cadena, 19, 21);
        
        g_print ("\n%s\n", cadena->str);
        g_string_free (cadena, TRUE);
}
	  

Introducir texto preformateado a un GString.

Esta es una de las aplicaciones más interesantes que podemos dar a un GString. Este tipo de datos nos permite trabajar con texto preformateado, como cuando trabajamos con un printf. Esta opción siempre es interesante, pues una vez que tengamos ese texto dentro del GString, podremos aprovecharnos de las múltiples facetas que posee este tipo.

La siguiente función, g_string_printf, recordará al lector a la ya conocida sprintf() de C estándar; la diferencia está en que el buffer tiene la capacidad de crecer automáticamente. Otra cosa a tener en cuenta en el uso de esta función es que cuando se usa, el contenido anterior existente (si existiese) es destruido.

void g_string_printf ( cadena ,  
  formato ,  
 ... ); 
GString *   cadena ;
const gchar   formato ;
 ... ;

Ejemplo 10. Crear texto preformateado con GString.

/* ejemplo del uso de g_string_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("");
        g_string_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                         frase, numero);
        
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
	  

GLib™ también dispone de una función similar a la anterior. La única diferencia estriba en que esta función añade el texto preformateado. Es decir, si tuvieramos un texto dentro del GString, el texto formateado se añadiría detrás del texto existente. Esto le puede resultar útil en el sentido de que la anterior función destruía el contenido anterior y puede que eso no le convenga.

void g_string_append_printf ( cadena ,  
  formato ,  
 ... ); 
GString *   cadena ;
const gchar   formato ;
 ... ;

Ejemplo 11. Añadir texto preformateado con GString.

/* ejemplo del uso de g_string_append_printf */
#include <glib.h>

main (){
        
        GString *cadena ;
        gchar *frase = "lo bueno, si breve, dos veces bueno" ;
        gint numero = 7 ;
        
        cadena = g_string_new ("Línea ya existente\n");
        g_string_append_printf (cadena, "FRASE TIPICA : %s\nNUMERO DE LA SUERTE : %d",
                                frase, numero);
        g_print ("%s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
	  

Otras funciones útiles para el manejo de GString.

En las secciones anteriores se han explicado las funciones más comunes con las que poder manejar una estructura del tipo GString, pero estas funciones no son las únicas que existen para trabajar con este tipo de datos. En la siguiente sección, se explicarán otras que, aunque no son tan fundamentales, pueden resultar útiles.

Para empezar, puede que al programador no le interese insertar o añadir una cadena y sólo quiera trabajar con un carácter. Para ello dispone de estas funciones que, aunque surten el mismo efecto que si usase g_string_append y similares, con un sólo carácter, puede que estas funciones le sirvan para dar más legibilidad a su código en un momento dado.

GString * g_string_append_c ( cadena ,  
  caracter ); 
GString *   cadena ;
gchar   caracter ;
GString * g_string_prepend_c ( cadena ,  
  caracter); 
GString *   cadena ;
gchar   caracter;
GString * g_string_insert_c ( cadena ,  
  posicion ,  
  caracter ); 
GString *   cadena ;
gssize   posicion ;
gchar *   caracter ;

Ejemplo 12. Añadir e insertar caracteres a un GString.

/* ejemplo del uso de g_string_{insert|append|prepend}_c */
#include <glib.h>

main (){
        
        GString *cadena;
        gchar caracter ;
        
        cadena = g_string_new ("");
        
        caracter = 'c' ;
        cadena = g_string_append_c (cadena, caracter);
        caracter = 'a' ;
        cadena = g_string_prepend_c (cadena, caracter);
        caracter = 'b' ;
        cadena = g_string_insert_c (cadena, 1, caracter);
        
        g_print ("la cadena resultante es... %s\n",cadena->str);
        g_string_free (cadena, TRUE);
        
}
	  

Otras acciones que pueden interesarle son la capacidad de truncar un texto por el lugar que usted desee y la capacidad de convertir todo el texto a mayúsculas o minúsculas. Pues para este tipo de necesidades usted dispone de g_string_truncate, cuya sintaxis se muestra a continuación.

GString * g_string_truncate ( cadena ,  
  longitud ); 
GString *   cadena ;
gsize   longitud ;

longitud se refiere al número de caracteres desde el principio de la cadena que desea que permanezcan una vez terminada la función.

GString * g_string_up ( cadena ); 
GString *   cadena ;
GString * g_string_down ( cadena ); 
GString *   cadena ;

La primera función, g_string_up, es la que convierte a mayúsculas un texto íntegro del GString y la segunda, g_string_down la que lo convierte en minúsculas.