Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: sebamoron86 en 27 Abril 2016, 15:25 pm



Título: Normalizacion de cadenas en C
Publicado por: sebamoron86 en 27 Abril 2016, 15:25 pm
Hola, tengo el siguiente problema tengo que normalizar una cadena de caracteres. La normalizacion consiste en que ingresado un texto el programa le borra los espacios en blanco del principio, pone la primer letra en mayúscula y las demás en minúscula, después hace lo mismo con la siguiente palabra.
Ejemplo
Citar
     hola     mUndo

Cita de: Normalizado
Hola mundo

El programa

Código:
#include <stdio.h>
#include <stdlib.h>
#include "personas.h"

int main()
{ char cad[50];
char *pos=cad,
     *des=cad;
    printf("Ingrese la cadena:");
    gets(cad);
    puts(cad);
    while(*pos)
    {
       while(esBlanco(*pos)) /*muevo pos hasta que encuentre texto*/
         pos++;
        if(*pos)
        {
            *des=aMayuscula(*pos); /*convierto la primer letra de la palabra en mayuscula*/
            pos++;
            des++;
        }
        while(*pos&&!esBlanco(*pos)) /*convierto las demas palabras en minusculas*/
        {
            *pos=aMinuscula(*pos);
            *des=*pos;
            pos++;
            des++;
        }

    }

    *des='\0';
    puts(cad);
    return 0;
}

Hace todo salvo que no deja el espacio entre las palabras sino que las deja pegadas. Pense en poner una bandera para que despues de salir de la primer palabra y despues de correr pos hasta la segunda palabra corra des un lugar. Pero no entiendo porque no funciona, se que debe ser una boludez pero no me puedo dar cuenta
Desde ya muchas gracias, saludos


Título: Re: Normalizacion de cadenas en C
Publicado por: MAFUS en 27 Abril 2016, 16:25 pm
Puedes optimizar un poco el código, como ves pos siempre se incrementa, por lo que lo podrías sacar de los ifs.
Ya que el bucle principal recorre todos los caracteres del array mejor si solo manejas el control de los caracteres dentro de él y no generas más bucles, aparte de redundantes te quitan control y complican la lógica.
Te será más fácil si llevas todas las letras a minúsculas y ya fuera del bucle haces mayúscula la primera letra.
Ya existen funciones de librería para saber si un carácter es un carácter blanco y para cambiar la capitalización (solo en caracteres ingleses).


Título: Re: Normalizacion de cadenas en C
Publicado por: HardForo en 27 Abril 2016, 16:43 pm
Creo te han dado una buena solucion, sin embargo si me pasas las funciones faltantes como esBlanco() etc podria depurarlo


Título: Re: Normalizacion de cadenas en C
Publicado por: sebamoron86 en 27 Abril 2016, 17:51 pm
Hola antes que nada muchas gracias por responder!!!
No entendí lo de los if, ¿vos decis hacer esto?
Código:
#include <stdio.h>
#include <stdlib.h>
#include "personas.h"

int main()
{ char cad[50];
char *pos=cad,
     *des=cad;
    printf("Ingrese la cadena:");
    gets(cad);
    puts(cad);
    while(*pos)
    {
       while(esBlanco(*pos)) /*muevo pos hasta que encuentre texto*/
         pos++;
        if(*pos)
          *des=aMayuscula(*pos); /*convierto la primer letra de la palabra en mayuscula*/
        pos++;
        des++;
        while(*pos&&!esBlanco(*pos)) /*convierto las demas palabras en minusculas*/
        {
            *pos=aMinuscula(*pos);
            *des=*pos;
            pos++;
            des++;
        }

    }

    *des='\0';
    puts(cad);
    return 0;
}

Y me olvide de avisar algo importante no se pueden usar las funciones de libreria de caracteres

Aca estan las funciones
Código:
#include"personas.h"

int esBlanco (char c)
{

    /*if (c==' '||c=='\t')
        return 1;
    return 0;*/



 return c==' '||c=='\t';

}

char aMayuscula(char c)
{
    //if(c>='a'&&c<='z')
     //  c-=32;
    c>='a'&&c<='z'? c-=32 :c;
    return c;
}

char aMinuscula(char c)
{
    c>='A'&&c<='Z'? c+=32 :c;
}


Gracias de nuevo


Título: Re: Normalizacion de cadenas en C
Publicado por: MAFUS en 27 Abril 2016, 18:33 pm
Algo así:
Código
  1. #include <stdio.h>
  2.  
  3. int tolower(int __c) {
  4.    if(__c >= 'A' && __c <= 'Z')
  5.        __c ^= 32;
  6.    return __c;
  7. }
  8.  
  9. int toupper(int __c) {
  10.    if(__c >= 'a' && __c <= 'z')
  11.        __c ^= 32;
  12.    return __c;
  13. }
  14.  
  15. int isblank(int __c) {
  16.    return __c == ' ' || __c == '\t';
  17. }
  18.  
  19. int main() {
  20.    char cad[50];
  21.    char *pos=cad;
  22.    char *des=cad;
  23.    int espacio_escrito = 0;
  24.  
  25.    printf("Ingrese la cadena: ");
  26.    fgets(cad, sizeof(cad), stdin);
  27.    puts(cad);
  28.  
  29.    while(*pos) {
  30.        if(isblank(*pos)) { /* Trato de todo tipo de espacios en blanco */
  31.            if(!espacio_escrito  && des != cad) { /* No se ha escrito el espacio en la cadena final Y no estamos en el primer carácter de la cadena final */
  32.                *des = ' ';
  33.                des++;
  34.                espacio_escrito = 1;
  35.            }
  36.        }        
  37.        else {
  38.            *des = tolower(*pos); /* Todo en minúscula */
  39.            des++;
  40.            espacio_escrito = 0;
  41.        }
  42.  
  43.        pos++;
  44.    }
  45.  
  46.    *des='\0';
  47.    cad[0] = toupper(cad[0]); /* Primera letra en mayúscula */
  48.  
  49.    puts(cad);
  50.    return 0;
  51. }


Título: Re: Normalizacion de cadenas en C
Publicado por: sebamoron86 en 28 Abril 2016, 16:00 pm
Gracias de nuevo por responder, antes de anda probé el código y anda perfecto
Código:
if(!espacio_escrito  && des != cad)
            { /* No se ha escrito el espacio en la cadena final Y no estamos en el primer carácter de la cadena final */
                *des = ' ';
                des++;
                espacio_escrito = 1;
            }

Primero no entiendo muy bien este  if(!espacio_escrito  && des != cad). ¿en la primer parte preguntas si espacio_escrito==0? y  tampoco entiendo porque entra la primer vez ya que des y cad para mi son iguales (des apunta al primer elemento de la cadena y tengo entendido que un el nombre de un char hace lo mismo)
Segundo no entiendo como con *des = ' ' se borran todos los espacios en blanco. Mi razonamiento (que se que esta mal) es: des siempre apunta a un elemento de la cadena, si el contenido es un espacio en blanco con esa linea lo estas igualando a otro espacio en blanco por lo que debería quedar igual.
Perdon si son preguntas muy básicas pero recién estoy empezando a programar y me cuesta mucho entender codigo escrito por otro, gracias de nuevo


Título: Re: Normalizacion de cadenas en C
Publicado por: MAFUS en 28 Abril 2016, 17:06 pm
Empecemos por el principio.
cad es el array que guarda la cadena en bruto. Se puede considerar cad como un puntero al primer elemento de dicho array.
pos es un puntero que recorre todo el array en bruto. De él se toman los caracteres para decidir que hacer con ellos.
des es un puntero que va a ser usado para formar el array nuevo. Solo se actualiza su posición cuando se ha soltado un carácter válido.

Para empezar hacemos que pos y des apunten al principio de cad.

Una bandera, espacio_escrito, sirve para saber si hemos escrito un carácter espacio y para marcar que no se escriban más en caso de que hubieren varios seguidos en la cadena en bruto.

Tip: en C, y para operaciones lógicas, todo valor 0 es falso y todo valor diferente de 0 es cierto.

Sí !espacio_escrito es igual a espacio_escrito==0.

Dentro del if que mira si estamos ante un espacio en blanco (un espacio o una tabulación) debemos mirar que no estemos al principio de la cadena nueva: no nos interesa poner espacios al principio de ella. Y esto es lo que hace des != cad: mira las direcciones a las que apuntan los dos punteros. Si son iguales no debemos escribir ningún espacio y por lo tanto saltamos todo el código de ese if.
De igual forma, si ya no estamos al principio de esa cadena, debemos mirar si con anterioridad hemos escrito un espacio o no, y eso es lo que hacemos mediante la bandera espacio_escrito. Si no se ha escrito un espacio debemos escribir uno y eso es lo que hace el código, además activamos la bandera a 1; así en los posteriores caracteres, si son blancos ya no escribiremos nada en la nueva cadena. Fíjate que, más adelante, nos encontramos un carácter no espacio en blanco, ponemos la bandera a 0.
Como consideramos espacios en blanco espacios y tabulaciones, y no nos interesa que en la cadena nueva haya tabulaciones, no podemos hacer *des = *pos porque *pos podría contener una tabulación. Para evitar esto y hacer que se escriba un espacio hacemos que *des = ' ', es decir escribamos un espacio en el caracter *des.