martes, 4 de enero de 2011

Kernighan_Ritchie_1.9 (Sustituir Varios Espacios en Blanco por Un Solo Espacio en Blanco en C)

_____________________________________________________________________________________
Kernigahn_Ritchie_1.9 Escriba un programa que copie su entrada a la salida, reemplazando cada cadena de uno o más espacios en blanco por un sólo blanco.
_____________________________________________________________________________________
SOLUCIÓN:
Este programa toma una cadena como entrada y la da como salida sustituyendo dos o más espacios en blanco, o tabuladores, por un sólo espacio en blanco. Contiene un par de instrucciones print que le avisan al usuario de qué va el programa. Sin embargo, tal vez preferiría comentarlas si quiere procesar un archivo mediante redireccionamiento de salida y entrada.
Para atacar el problema, debe dividirse cada carácter leído en dos grupos: es espacio (simple o tabulaor) o no lo es. Si el espacio leído no es espacio simple ni tabulador, debe imprimirse, porque es un carácter literal o numérico (o cualquiera de los otros que conforman el código ASCII). Si es un espacio en blanco o tabulador, debe imprimirse un espacio simple sólo si antes no se ha impreso un espacio simple. Para llevar el control de ésto es necesario el uso de una variable auxiliar, que en el programa se llama 'anterior'.


/*//////////////////////////////////////////////////////////////////////////
//                                                                        //
// Este programa recibe una cadena y la imprime en la salida estandar     //
// sin espacios dobles, triples, etc. o tabuladores                       //
//////////////////////////////////////////////////////////////////////////*/

/*//////////////////////////////////////////////////////////////////////////
//                                                                        //
//                        ALGORITMO:                                      //
//                                                                        //
//  Se requiere dos variables:                                            //
//       c (caracter leido)                                               //
//       caracter_anterior                                                //
//                                                                        //
//  Lee un caracter                                                       //
//  Mientras el caracter (c) sea distinto de EOF                          //
//  {                                                                     //
//  Si c != ' ' (si el caracter no es un espacio)                         //
//        Si c != '\t'   (si el caracter no es un tabulador)              //
//            Imprime el caracter                                         //
//            caracter_anterior = letra (esta variable recuerda que el    //
//                                       caracter anterior no fue espacio //
//                                       o tabulador)                     //
//                                                                        //
//                                                                        //
//  Si c == ' ' (si el caracter es un espacio)                            //
//        Si caracter_anterior fue una letra                              //
//            Imprime el espacio                                          //
//            caracter_anterior = espacio (esta variable ahora recuerda   //
//                                         que el caracter anterior fue   //
//                                         un espacio)                    //
//  Si c == ' ' (si el caracter es un tabulador)                        //
//        Si caracter_anterior fue una letra                              //
//            Imprime el espacio                                          //
//            caracter_anterior = espacio (esta variable ahora recuerda   //
//                                         que el caracter anterior fue   //
//                                         un espacio)                    //
//                                                                        //
//                                                                        //
//                                                                        //
//  Lee un caracter                                                       //
//  }                                                                     //
//////////////////////////////////////////////////////////////////////////*/

#include<stdio.h>

int main()
{                    /* Abre main */

/*Comentar las instrucciones print para recibir un archivo como entrada*/
printf("\nEste programa toma una cadena como entrada y la da como salida");
printf(" sustituyendo dos o mas espacios en blanco por un solo espacio en blanco.");
printf("\nIntroduzca una cadena: (EOF para terminar)\n");

int anterior;
int c;

while ( (c = getchar()) != EOF )
{                    // Abre while

 /*////////////////////////////////////////////////////////////////////////
 // Si el caracter es distinto de espacio
 ////////////////////////////////////////////////////////////////////////*/
 
if (' ' != c )

{  /* abre primer if */

/*/////////////////////////////////////////////////////////////////////////
// si el caracter es distinto de tabulador
/////////////////////////////////////////////////////////////////////////*/
if ('\t' != c ) /*Este if puede suprimirse si se utiliza
  un && en el if precedente*/
{       /*Abre if anidado*/ 
putchar(c);
anterior = 'l';  /*La variable anterior toma el valor 'l', letra */

}  /*Cierra if anidado*/
}       /* Cierra primer if */

/*/////////////////////////////////////////////////////////////////////////
// Si el caracter es un espacio
/////////////////////////////////////////////////////////////////////////*/
if ( ' ' == c )
{       /* Abre if */

if ( 'l' == anterior )  /* El programa checa si ya hay un espacio*/
{
printf(" ");
anterior = 'b';   /* La variable anterior toma el valor 'b', blanco */
}
}       /* Cierra if */

/*/////////////////////////////////////////////////////////////////////////
// si el caracter es un tabulador
/////////////////////////////////////////////////////////////////////////*/

if ( '\t' == c ) /*Este if puede suprimirse si se utiliza un 
  operador || en el if precedente*/
{       /* Abre if */

if ( 'l' == anterior )  /* El programa checa si ya hay un espacio*/
{
printf(" ");
anterior = 'b';   /* La variable anterior toma el valor 'b', blanco */
}
}       /* Cierra if */

}                // Cierra while

}                    /* Cierra main*/


El mismo código, un poco más corto, haciendo uso de los operadores && (AND lógico) y || (OR lógico) y sin comentarios.

#include<stdio.h>

int main()
{                    /* Abre main */

/*Comentar las instrucciones print para recibir un archivo como entrada*/
printf("\nEste programa toma una cadena como entrada y la da como salida");
printf(" sustituyendo dos o mas espacios en blanco por un solo espacio en blanco.");
printf("\nIntroduzca una cadena: (EOF para terminar)\n");

int anterior;
int c;

while ( (c = getchar()) != EOF )
{                    // Abre while

if (' ' != c && '\t' != c)

{  /* abre if */
putchar(c);
anterior = 'l';  /*La variable anterior toma el valor 'l', letra */

}       /* Cierra if */

if ( ' ' == c || '\t' == c )
{       /* Abre if */

if ( 'l' == anterior )  /* El programa checa si ya hay un espacio*/
{
printf(" ");
anterior = 'b';   /* La variable anterior toma el valor 'b', blanco */
}
}       /* Cierra if */

}                // Cierra while

}                    /* Cierra main*/

______________________________________________________________________________
Este programa es parte de los problemas resueltos del libro El Lenguaje de Programación C de B.kernighan y D. Ritchie.
Entrada Anterior
Entrada Siguiente

23 comentarios:

  1. Hola, estoy con el libro de kernighan y ritchie, encontre tu pagina buscando la solucion de este ejercicio, el 1.9, pero veo que usas los siguientes operadores // && y en el libro no se menciona esto antes del ejercicio 1.9, quisiera saber como resolver esto sin usar esos operadores..

    y cuando escribis anterior = 'b' no sera anterior= '\b'

    gracias, muy buena la pagina..

    saludos..

    ResponderEliminar
    Respuestas
    1. Acabo de escribir una versión del programa sustituyendo los operadores lógicos && y ||, por condicionales if. Un && se cambia por un if anidado y un || por un if externo. Con respecto a 'b', no se trata de la secuencia de escape \b sino de el valor de la letra b en código ASCII. Sólo sirve para llevar el control de la variable anterior, cuyo uso explico en los comentarios. Saludos y muchas gracias.

      Eliminar
    2. haa.. yo pensaba que ese ejemplo ya estaba ahi y no lo habia visto.. gracias..

      estoy empesando C con este libro..

      Eliminar
    3. Gracias. Algunos de éstos programas son complicados. Cualquier duda me puedes escribir un comentario. Saludos.

      Eliminar
  2. Me respondo solo, no se como no vi el primer ejemplo!! Y ya entendi que es lo que hace anterior = 'b'

    saludos

    ResponderEliminar
  3. disculpa por la molestia.. escribi el programa pero de otra forma y no funciona, o realizando peque;os cambios funciona en la primera linea pero en las siguientes no funciona.. el programa es este:

    #include

    main()
    {
    int a,b=0;

    while ((a=getchar())!=EOF)
    {
    if (a!=' ')
    {
    putchar(a);
    ++b;
    }
    if (a==' ')
    {
    if (b<0)
    {
    printf(" ");
    b=0;
    }
    }
    }
    }

    ResponderEliminar
    Respuestas
    1. Lo único que tienes que hacer es cambiar la línea
      if (b<0)
      por
      if (b>0)

      Eliminar
    2. Jaja, gracias.. soy un bol... por confundirme los signos.. gracias nuevamente..

      Eliminar
  4. hola:
    gracias por tu aportaciòn. No sabes como me di de topes para resolverlo, con puros if.
    seria mucha molestia si pudieses hacer el diagrama de flujo, ya que soy novato y quisera aprender tambien como manejar los diagramas de flujo; o si me pudieses pasar el link de alguna página donde se explique a detalle como hacer algoritmos.
    muchas gracias.

    ResponderEliminar
    Respuestas
    1. ¡Hola! Gracias a ti por el comentario. Ahora no tengo ningún diagrama de flujo, pero como parte de un curso de C que estoy escribiendo, pretendo subir algunas entradas relacionadas. Con lo de los algoritmos también te lo debo, aunque te recomiendo que revises las entradas en el mencionado Curso de C Ahí tengo problemas explicados línea a línea.
      Saludos.

      Eliminar
  5. tengo una duda con la lectura de carácter, caracter se refiere a toda una oracion por ejemplo y de ahi busca donde hay mas de dos espacios en blanco y los cambia por solo uno o caracter se refiere solo un numero,una letra?

    ResponderEliminar
  6. Dime por favor si me equivoco en mi forma de enteder el funcionamiento del getchar, asi lo entiendo: Getchar toma cada caracter que escribo y es asignado a la variable c y es ejecutado while mientras no escriba EOF. No toma toda una oracion como un solo caracter sino cada frase por asi decirlo y lo compara con el while y de ahi se ejecuta el programa hasta que ponga el End Of File (Contrl + z)y por ultimo imprime en pantalla ya corregido Cierto?

    ResponderEliminar
    Respuestas
    1. Vas bien hasta que dices ",,, sino cada frase..". Un carácter es cualquiera de los 256 símbolos (algunos se imprimen, como a, b, c, A, B, C,...) que usa tu computadora para introducir información. Puedes checar el código ascii para investigarle más. Cada carácter tiene un valor, que va desde 0 hasta 255. Lo que hace getchar es recibir cada caracter y realizar el ciclo mientras sea distinto a EOF (casi siempre es -1). C puede recibir cadenas (strings) pero con otras funciones. Si aprendes bien el uso de getchar vas a poder realizar un montón de ejercicios de manipulación de caracteres.
      Muchos saludos, Félix.

      Eliminar
    2. De nuevo gracias tu ayuda es muy clara así si me dan ganas de seguir practicando y aprender aunque sea poco a poco.Amigo muchas thxs.

      Eliminar
  7. Esto va viento en popa, parece que las desveladas están dando resultado. :)

    ResponderEliminar
    Respuestas
    1. La verdad, me da mucho gusto. Creo que elegiste el mejor libro para aprender.

      Eliminar
  8. Gracias, por compartir tu codigo.

    ResponderEliminar
    Respuestas
    1. Gracias, anónimo, por tu comentario. Que bueno que te sirva. saludos.

      Eliminar
  9. while((c = getchar()) != EOF)
    {
    if(c != ' ')
    putchar(c);
    }

    ¿Esto no es mas facil?

    ResponderEliminar
  10. una pregunta al declarar la funcion main como un entero (int main()) al final no hay que poner un return 0

    ResponderEliminar
  11. Mi solucion convierte cualquier cantidad de espacios en blanco o tabuladores juntos o separados, todo, en un solo espacio en blanco:
    #include
    main()
    {
    int c,b=0,d;
    while ((c=getchar()) != EOF)
    {
    if (c == '\t'){
    if (c == '\t' && d != '\t' && b !=' '){
    d=c;
    putchar (' ');
    }
    }
    else if (c != ' ' || b != ' ' && d != '\t'){
    b = c;
    putchar (c);
    d=c;
    }
    }
    }

    ResponderEliminar
  12. La solución del autor es la adecuada, ya que utiliza todos las funciones que
    hemos visto durante el capítulo 1.

    He utilizado otra forma que utiliza un contador por cada "espacio" utilizando lo estudiado en el capítulo 1.

    #include

    int main()
    {
    int espacio;
    int c;
    espacio = 0;

    while ((c=getchar())!=EOF)
    {
    if (c!=' ')
    {
    putchar(c);
    espacio=0;
    }
    if (c==' ')
    {
    espacio=espacio + 1;
    if (espacio==1)
    {
    putchar(' ');
    espacio = espacio + 1;
    }
    if (espacio>2)
    {
    putchar(c);
    putchar('\b');
    espacio=1;
    }
    }
    }
    }

    ResponderEliminar

Related Posts Plugin for WordPress, Blogger...