[C con Clase] Tratamiento de cadenas

Steven R. Davidson vze266ft en verizon.net
Mar Ene 29 17:03:36 CET 2008


Hola Alejandro,

Alejandro wrote:

> ¡Hola lista! Tengo un pequeño problema con una función que realiza
> cierto tratamiento sobre una cadena. Éste es el código de la función:
> 

[CORTE]

> 
> Pues bien, lo que yo quiero es que me transforme una cadena del tipo
> "Vaya! %j le ha dado un buen golpe a %o!". Decha cadena estaría en un
> arcjivo de texto y lo que quiero es que sustituya los caracteres "%j"
> y "%o" por los nicks de un jugador y su oponente. Dichos nicks se
> introducen al principo del programa. Ahora voy a contar mi problema.
> Si la cadena es como dije y acaba con un caracter normal, no tengo
> ningún problema. Pero cuando la cadena que intento tratar acaba por
> "%o" o por "%j" se me añaden unas sopechosas símbolos al final de la
> cadena, tras un salto de línea. Supongamos que el nick del jugador es
> "Jug1" y el del oponente es "Opon". Pues si yo intento tratar la
> cadena "Vaya! Un gran ataque de %j golpea a %o!" el resultado es:
> "Vaya! Un gran ataque de Jug1 golpea a Opon!". Perfecto. Sin embargo,
> si yo intento tratar la cadena "Vaya! Un gran ataque de %j golpea a
> %o" el resultado es: "Vaya! Un gran ataque de Jug1 golpea a Opon
> w2s". Además de w2s me aparecen otros símbolos raros, hasta completar
> un total de cuatro. Dichos símbolos aparecen tras un salto de
> línea... ¿A qué se debe?
> 

Tienes un error al usar 'auxiliar' cuando quieres asignar el valor de 0 
inicialmente. Escribes:

for( int y = 0; auxiliar[y]; y++ )
{
   auxiliar[y] = 0;
}

Como 'auxiliar' no fue inicializado, éste contiene basura. Además, lo 
que realmente quieres es usar el valor de 512, porque es el valor 
máximo. Esto sería,

for( int y = 0; y < 512; y++ )
{
   auxiliar[y] = 0;
}

El otro problema es que no asignas el carácter nulo al final de la 
cadena en 'definitiva'. Ten presente que estás construyendo una cadena 
de caracteres desde cero y por tanto necesitas agregar un cero al final.


De todos modos, sugiero usar las funciones estándares de <cstring> para 
realizar estas manipulaciones. Específicamente, las funciones 'strchr()' 
y 'strncat()'. La primera sirve para buscar un carácter en una cadena y 
la segunda para copiar x caracteres de una cadena al final de otra. El 
esquema del algoritmo sería algo así:

1.  Buscar '%' en la cadena: original
2.  Copiar la subcadena de original hasta '%' al final de: resultado
3.  Si el siguiente carácter es 'j', entonces
4.     Copiar jugador.nombre al final de resultado
5.  Si no y el siguiente carácter es 'o', entonces
6.     Copiar oponente.nombre al final de resultado
7.  Repetir los pasos #1-#6 hasta que lleguemos al final de original
8.  Terminar( resultado )

Básicamente vamos encontrando y copiando subcadenas en la cadena 
original. Estamos haciendo algo parecido a esto:

char szResultado[512];

strcpy( szResultado, "Vaya! " );
strcat( szResultado, jugador.nombre );
strcat( szResultado, " le ha dado un buen golpe a " );
strcat( szResultado, oponente.nombre );
strcat( szResultado, "!" );


Otra solución podría ser la siguiente. Encontrar cada pareja "%j" y "%o" 
y sustituirlos por "%s". Posteriormente, invocamos 'sprintf()' pasando 
las cadenas necesarias. El comportamiento sería el siguiente:

formato <- "Vaya! %j le ha dado un buen golpe a %o!"

Lo convertimos a:

"Vaya! %s le ha dado un buen golpe a %s!"

Ahora invocamos 'sprintf()':

sprintf( szResultado, formato, jugador.nombre, oponente.nombre );

Lo problemático sería saber cuáles y cuántos parámetros pasar a 
'sprintf()'. Si ya conoces los mensajes y los parámetros que existen, 
entonces es sencillo. Si no, entonces tenemos que usar 'vsprintf()' y 
construir una lista de parámetros. Como son cadenas de caracteres, 
necesitamos un array de punteros a 'char'. Algo como,

char *lista[10];

switch( nParam )
{
   case 2:
     lista[0] = jugador.nombre;
     lista[1] = oponente.nombre;
   case 3:
     lista[0] = jugador1.nombre;
     lista[1] = jugador2.nombre;
     lista[2] = oponente.nombre;
   case 4:
     lista[0] = jugador1.nombre;
     lista[1] = jugador2.nombre;
     lista[2] = oponente1.nombre;
     lista[3] = oponente2.nombre;
}

sprintf( szResultado, formato, (va_list)lista );

Para una explicación de las macros de <cstdarg>, puedes consultar el 
capítulo 20 yendo a: 
http://c.conclase.net/curso/index.php?cap=020#PAR_VARIABLES  y su 
referencia: http://c.conclase.net/librerias/libreria.php?lib=stdarg


Espero que esto te ayude.

Steven







Más información sobre la lista de distribución Cconclase