4

Deseo ingresar por consola un char array, luego tomarlo y dividirlo por palabras para así, cada palabra, compararla con otros aspectos para sacar su significado en otro idioma.

El problema es que no logro hacer el split de el char sentence ya que al ser una oración ingresada, no me llena todos los espacios. En este caso es de tamaño 20 pero podría ponerle de tamaño 100, pero cuando trato de hacer la división me saca otros caracteres ASCII que no los incluyo yo.

El código es el siguiente. Uno de los problemas es que no se puede utilizar string.h o cualquier clase de string:

#include <conio.h>
#include <stdio.h>
#include <iostream>
#include <windows.h>


int main(){
   getch();
   // sentence: oración que ingreso
   char sentence[20];

   cout<<"Ingrese una oracion o palabra"<<endl;
   cin.getline(sentence,20);
   int x = sizeof(sentence);
   int y;
   for(int a=0; a < x; a++){
            // trato de definir qué direcciones voy a tomar en cuenta 
            // para imprimir desde allí
            if((sentence[a] != ' ')&&(sentence[a+1] == ' ')){
                for(int z = y; z <= a; z++ ){
                    cout<<sentence[z];
                }
                // le sumo a y el valor de a para guardar desde dónde vuelvo a imprimir.
                y = a;          
            }

   }

   getch();
   cout<<sentence[9];
   getch();
   return 0;
}

También me gustaría saber si se puede transformar un char en char[]. Algo así...

#include <iostream>
#include <windows.h>

int main(){
    char ingreso;
    cout<<"ingreso"<<endl;
    cin.getline(ingreso,20);
    getch();
    // char ingreso2[] = ingreso;
    getch();
    cout<<ingreso;
    getch();
    return 0;
}
PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
Joe
  • 41
  • 2

2 Answers2

4

El problema es que no logro hacer el split de el char sentence ya que al ser una oración ingresada.

Tienes ejemplos de cómo hacer una división de cadenas (split) en este hilo:

¿Cómo separar las palabras que contiene un string en C++? 'Split '

Ya que has etiquetado tu pregunta como C++ (y estás usando objetos C++) deberías evitar todas las cabeceras C, lee este hilo para más detalles. Dicho esto, abordemos tu objetivo, ligeramente modificado:

Deseo ingresar por consola una frase, luego dividirla por palabras.

Con los consejos anteriores, tu código podría parecerse a esto:

template <typename char_type>
using string_collection = std::vector<std::basic_string<char_type>>;

template <typename char_type>
string_collection<char_type> split(const std::basic_string<char_type> &text)
{
    using string = std::basic_string<char_type>;
    using iterator = std::istream_iterator<string, char_type>;

    std::basic_stringstream<char_type> reader(text);
    return {iterator(reader), iterator()};
}

int main(){
   std::string sentence;
   std::cout << "Ingrese una oracion o palabra\n";
   std::getline(std::cin, sentence);

    for (const auto &palabra : split(sentence))
        std::cout << palabra << '\n';

   return 0;
}

Puedes verlo funcionando en Wandbox.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • 2
    No puede usar `std::string` o derivados – eferion Mar 12 '19 at 09:42
  • 1
    Voy a ahorrarme la retahíla de improperios que se me ocurren y lo voy a resumir así: ¿A santo de qué @Joe tiene prohibido usar `std::string`? Si es un ejercicio académico (que no me lo pareció) quienquiera que esté dando clases está haciendo un pésimo trabajo. – PaperBirdMaster Mar 12 '19 at 09:51
  • Coincido plenamente, yo solo te lo he dicho porque yo no lo he visto hasta que no le he dado un repaso a la pregunta – eferion Mar 12 '19 at 09:51
  • Yo tampoco lo he visto hasta que lo has señalado, pero no voy a cambiar mi respuesta para promover malas prácticas. Que me vote negativo quien así lo crea conveniente. – PaperBirdMaster Mar 12 '19 at 09:54
  • gracias por la respuesta colegas. Me dejan impresionado de lo bien que responden para que uno pueda comprender. Aún me falta mucho en progra. hay veces que me siento todo confundido sobre qué o dónde aprender más. Creo que lo más importante es la lógica a comparasión del lenguaje no? Gracias por su ayuda. – Joe Mar 13 '19 at 03:56
2
int x = sizeof(sentence);

sizeof es un operador que se evalúa en tiempo de compilación, es decir, el resultado lo calcula automáticamente el compilador. ¿Sabe el compilador qué va a introducir el usuario en cada momento? Obviamente no, así que sizeof no puede devolverte la longitud de la cadena.

sizeof indica la cantidad de memoria que ocupa una variable u objeto. En tu caso sentence, que es un array de 20 caracteres, ocupara 20 bytes en memoria (1 char == 1 byte) independientemente de la longitud del texto que almacene.

Para conocer la longitud de la cadena almacenada puedes usar strlen, de la librería cstring:

int x = std::strlen(sentence);

Seguidamente intentas separar la frase en palabras... aquí cometes otro error:

for(int a=0; a < x; a++){
  if((sentence[a] != ' ')&&(sentence[a+1] == ' ')){

Fíjate que a se mueve en el rango [0,x-1], que por cierto, nota que es un intervalo cerrado. Pues, bien, si a==x-1, la comprobación sentence[a+1] está comprobando un valor fuera del rango de la cadena. sentence[x] debería tener, siempre el caracter nulo que finaliza las cadenas.

Para dividir una cadena en palabras puedes usar strtok:

for( char* ptr = strtok(sentence," "); *(ptr = strtok(nullptr, " ")) != '\0'; )
{
  std::cout << ptr << '\n';
}

Aunque yo sugeriría usar std::string. En este caso podrías atacar el problema de varias maneras. Una en la que tendrías que escribir bastante poco código seŕia la siguiente:

  • Lees la línea completa en un std::string (no tienes que preocuparte por la longitud del texto)
  • Vuelcas el contenido del string en un stream de tipo istringstream
  • Lees el contenido del stream con el operador de extracción (extraes cada palabra de la frase)

Dicho con código:

std::string sentence;
std::getline(std::cin, sentence);

std::istringstream iss(sentence);
std::string word;
while( iss >> word )
{
  std::cout << word << '\n';
}

también me gustaría saber si se puede transformar un char en char[]

Eso sería como decir que te gustaría convertir un ladrillo en una casa. char[] es un array, donde cada elemento de ese array es de tipo char, luego no, no es posible convertir un elemento simple en una colección de elmentos simples.

Otra cosa es que estés mezclando conceptos y que tu intención sea copiar el contenido de ingreso en ingreso2. En este caso ambas variables tendrían que ser arrays de caracteres. Bajo estas condiciones, para copiar el contenido tendrías que llamar a funciones heredadas de C, como strcpy

char ingreso[21]; // <<--- no olvides la longitud del array
char ingreso2[21];
strcpy(intreso2, ingreso);

Claro que, por otro lado, el código sería más legible si usases std::string en vez de elementos heredados de C:

std::string ingreso;
std::string ingreso2;
ingreso2 = ingreso; // <<--- Esto ahora si funciona

Uno de los problemas es que no se puede utilizar string.h o cualquier clase de string

Bueno, en ese caso te toca implementar las funciones strlen y strtok a mano... tampoco son nada del otro mundo:

La función strlen tiene que devolver el número de caracteres de una cadena de texto dada. Sabemos que hemos llegado al final de la cadena cuando encontramos el caracter nulo:

size_t strlen(char const* ptr)
{
  size_t toReturn;

  for( toReturn = 0; *ptr != '\0'; ++ptr, ++toReturn );

  return toReturn;
}

Claro que también se puede sacar con aritmética de punteros:

size_t strlen(char const* ptr)
{
  char const* end = ptr;

  for( end = ptr; *end != '\0'; ++end );

  return ptr - end;
}

La función strtok es un poco más compleja, pero no mucho. Utiliza un puntero interno para poder trocear la cadena:

char* strtok(char * cadena, char const* delimitadores)
{
  static char* ptr = nullptr;

  if( cadena != nullptr )
    ptr = cadena;

  char* toReturn = ptr;
  for( char* ptr2 = ptr; ; ++ptr2 )
  {
    if( *ptr2 == '\0' )
    {
      ptr = ptr2;
      break;
    }

    bool is_delim = false;
    for( char const* delim = delimitadores; *delim != '\0'; ++delim )
      is_delim |= *delim == *ptr2;

    if( is_delim )
    {
      *ptr2 = '\0';
      ptr = ptr2 + 1;
      break;
    }
  }


  return toReturn;
}
eferion
  • 49,291
  • 5
  • 30
  • 72