Foros del Web » Programación para mayores de 30 ;) » C/C++ »

[SOLUCIONADO] Duda puntual: Cadenas de fechas

Estas en el tema de Duda puntual: Cadenas de fechas en el foro de C/C++ en Foros del Web. Hola chic@s Tengo un problemilla y es que no me viene a la mente como solucionar el siguiente problema: Tengo este programa de test: @import ...
  #1 (permalink)  
Antiguo 17/04/2016, 16:50
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Duda puntual: Cadenas de fechas

Hola chic@s
Tengo un problemilla y es que no me viene a la mente como solucionar el siguiente problema:

Tengo este programa de test:
Código C++:
Ver original
  1. FCT_TEST_BGN(Fecha - Comparacion: desigualdad) {
  2.       const Fecha f(1, 2, 2000);
  3.       const Fecha g(f);
  4.       const Fecha h(2, 3, 2001);
  5.       fct_chk(!(f != g));
  6.       fct_chk(f != h);
  7.       fct_chk(f != "00002/003/02001"); // Problema en esta linea
  8.       fct_chk("1/1/2001" != g);
  9. }

Mi constructor a partir de una cadena de la siguiente manera:
Código C++:
Ver original
  1. Fecha::Fecha (const char *fecha){
  2.     int iCheck;
  3.  
  4.     iCheck = sscanf(fecha, "%02d/%02d/%04d", &iDia_, &iMes_, &iAno_);
  5.     if(iCheck == 3){
  6.         fecha_actual();
  7.         if(!es_valida(iDia_, iMes_, iAno_))
  8.             throw Invalida("Error: No ha introducido una fecha correcta"); 
  9.     }
  10.     else{
  11.         throw Invalida("Error: Formato de fecha no valido. Formato valido: dd/mm/aaaa");
  12.     }
  13. }

El caso es que me da el siguiente problema:
Código:
terminate called after throwing an instance of 'Fecha::Invalida'
Fecha - Comparacion: desigualdad ..................................Abortado
La clase Invalida está dentro de la clase Fecha:
Código C++:
Ver original
  1. class Invalida {
  2.     public:
  3.         Invalida(const char* cError) : cError_(cError) {}
  4.         const char* por_que() const noexcept;
  5.  
  6.     private:
  7.         const char* cError_;
  8. };

No sabría como solucionar esa devolución del error.
Muchas gracias por su tiempo

PD: no sé si debería controlar la cantidad de ceros a la izquierda, ya que el otro método de test de fecha incorrecta funciona correctamente
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds

Última edición por agusax; 17/04/2016 a las 16:56
  #2 (permalink)  
Antiguo 18/04/2016, 02:03
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Duda puntual: Cadenas de fechas

Está claro que si tu clase Fecha tiene que entender que 00004 puede ser un día válido no tiene sentido limitar la entrada de sscanf a 2 caracteres.

Código C++:
Ver original
  1. iCheck = sscanf(fecha, "%d/%d/%d", &iDia_, &iMes_, &iAno_);

Esta versión no te debería dar esos problemas.

Otra cosa es que esa fecha se tenga que interpretar como no válida... en cuyo caso lo que no tiene sentido es que devuelvas una excepción en el constructor de la clase Fecha. En este caso tendrías que tener un booleano interno en Fecha que indicase si la fecha almacenada es válida. Al realizar las comparaciones, si una fecha es válida y la otra no automáticamente ambas fechas van a ser diferentes. O eso o haces una sobrecarga del operador de comparación específica:

Código C++:
Ver original
  1. class Fecha
  2. {
  3.   // versión 1
  4.   bool operator!=(const char* fecha) const;
  5.  
  6.   // versión 2
  7.   friend bool operator!=(const Fecha& fecha1, const char* fecha2);
  8. };

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #3 (permalink)  
Antiguo 18/04/2016, 02:42
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Respuesta: Duda puntual: Cadenas de fechas

Cita:
Iniciado por eferion Ver Mensaje
Está claro que si tu clase Fecha tiene que entender que 00004 puede ser un día válido no tiene sentido limitar la entrada de sscanf a 2 caracteres.

Código C++:
Ver original
  1. iCheck = sscanf(fecha, "%d/%d/%d", &iDia_, &iMes_, &iAno_);

Esta versión no te debería dar esos problemas.

Otra cosa es que esa fecha se tenga que interpretar como no válida... en cuyo caso lo que no tiene sentido es que devuelvas una excepción en el constructor de la clase Fecha. En este caso tendrías que tener un booleano interno en Fecha que indicase si la fecha almacenada es válida. Al realizar las comparaciones, si una fecha es válida y la otra no automáticamente ambas fechas van a ser diferentes. O eso o haces una sobrecarga del operador de comparación específica:

Código C++:
Ver original
  1. class Fecha
  2. {
  3.   // versión 1
  4.   bool operator!=(const char* fecha) const;
  5.  
  6.   // versión 2
  7.   friend bool operator!=(const Fecha& fecha1, const char* fecha2);
  8. };

Un saludo.
Ya probé a poner sscanf(fecha, "%d/%d/%d", &iDia_, &iMes_, &iAno_), pero entonces no me pasa después el test de desbordamiento, debería ser una fecha inválida.
Mi operador de comparación es de este modo:
Código C++:
Ver original
  1. bool operator == (const Fecha& f1, const Fecha& f2){
  2.     return ((f1.dia() == f2.dia()) && (f1.mes() == f2.mes()) && (f1.anno() == f2.anno()));
  3. }
  4.  
  5. bool operator != (const Fecha& f1, const Fecha& f2){
  6.     return !(f1 == f2);
  7. }

Se supone que el constructor, lo uso para almacenar los valores de la cadena en iDia, iMes, iAno

Muchas gracias por responder
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds
  #4 (permalink)  
Antiguo 18/04/2016, 03:10
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Duda puntual: Cadenas de fechas

Cita:
Iniciado por agusax Ver Mensaje
Ya probé a poner sscanf(fecha, "%d/%d/%d", &iDia_, &iMes_, &iAno_), pero entonces no me pasa después el test de desbordamiento, debería ser una fecha inválida.
Entonces sscanf no es una opción para tí.

Puedes optar por varias posibilidades:

  • Si estás compilando bajo el estándar C++11 (2011) o posterior puedes usar las expresiones regulares para recuperar los elementos de la fecha.
  • Puedes usar strtok para trocear la cadena por los separadores y después comparar cada elemento (día,mes,año) por separado: verificar que todos los dígitos son numéricos, verificar que es un número válido y que está dentro del rango de valores correcto).
  • Puedes hacer el proceso descrito en el paso anterior pero todo a mano.

Cita:
Iniciado por agusax Ver Mensaje
Mi operador de comparación es de este modo:
Puedes optar por tener tantos operadores como necesites... que tengas ya uno implementado no quiere decir que no puedas tener más si así lo requiere el diseño.

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #5 (permalink)  
Antiguo 18/04/2016, 03:38
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Respuesta: Duda puntual: Cadenas de fechas

Este es mi test del desbordamiento
Código C++:
Ver original
  1. FCT_TEST_BGN(Fecha - Extraccion: desbordamiento) {
  2.       istringstream is("007/007/1997");
  3.       Fecha f;
  4.       fct_chk_ex(Fecha::Invalida, is >> f);
  5.     }

Esto es lo que me comenta el profesor:
Cita:

La Fecha "00002/003/02001" es válida porque es "2/3/2001": 2 de marzo de 2001. La Fecha "007/007/1997" también: "7/7/1997", 7 de julio de 1997; pero en este 2.º caso se está leyendo de un flujo de entrada; la lectura en este caso debería limitarse a 2+1+2+1+4=10 caracteres como mucho: el desbordamiento es en el flujo de entrada, no en la Fecha.

Pista: width o setw: http://en.cppreference.com/w/cpp/io/manip/setw
Por eso con el sscanf me da error la prueba de desbordamiento.
El problema es que no sé como utilizar eso.
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds

Última edición por agusax; 18/04/2016 a las 03:43
  #6 (permalink)  
Antiguo 18/04/2016, 04:10
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Duda puntual: Cadenas de fechas

Cita:
Iniciado por agusax Ver Mensaje
Esto es lo que me comenta el profesor:
En ese caso tienes que tener un constructor específico para istream (buffers de entrada) y otro para char*, de tal forma que el constructor de istream realice un chequeo de desbordamiento mientras que el de char* no debe realizar dicho chequeo.

Código C++:
Ver original
  1. Fecha::Fecha(const char* cad); // Sin desbordamiento
  2. Fecha::Fecha(istream& stream); // Con desbordamiento

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #7 (permalink)  
Antiguo 18/04/2016, 04:22
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Respuesta: Duda puntual: Cadenas de fechas

Añado mi flujo de entrada:

Código C++:
Ver original
  1. istream& operator >>(istream& flujo, Fecha& fecha){
  2.     char* cadAuxiliar = new char [flujo.width()];
  3.  
  4.     flujo >> cadAuxiliar;
  5.     fecha = cadAuxiliar;
  6.     delete [] cadAuxiliar;
  7.  
  8.     return flujo;
  9. }
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds
  #8 (permalink)  
Antiguo 18/04/2016, 04:27
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Respuesta: Duda puntual: Cadenas de fechas

ACABO DE SOLUCIONARLO:

He actualizado el flujo de entrada de los datos y ya me pasa todos los test correctamente, mirando el desbordamiento también.

Código C++:
Ver original
  1. istream& operator >>(istream& flujo, Fecha& fecha){
  2.  
  3.     char* entrada = new char[11];
  4.     flujo >> setw(11) >> entrada;
  5.     fecha = Fecha(entrada);
  6.     return flujo;
  7. }

Muchas gracias por tu tiempo :D
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds
  #9 (permalink)  
Antiguo 18/04/2016, 04:30
 
Fecha de Ingreso: octubre-2014
Ubicación: Madrid
Mensajes: 1.212
Antigüedad: 10 años, 1 mes
Puntos: 204
Respuesta: Duda puntual: Cadenas de fechas

Vale, lo que te falta ahora es llamar al método que comprueba el desbordamiento:

Código C++:
Ver original
  1. istream& operator >>(istream& flujo, Fecha& fecha){
  2.     char* cadAuxiliar = new char [flujo.width()];
  3.  
  4.     flujo >> cadAuxiliar;
  5.     fecha.ComprobarDesbordamiento(cadAuxiliar); // O como se use
  6.     fecha = cadAuxiliar;
  7.     delete [] cadAuxiliar;
  8.  
  9.     return flujo;
  10. }

En cualquier caso... ¿por qué usas char* en vez de la clase std::string? Si es una exigencia de tu profesor vale... en caso contrario deberías cambiar esos usos:

Código C++:
Ver original
  1. istream& operator >>(istream& flujo, Fecha& fecha){
  2.     std::string cadAuxiliar;
  3.  
  4.     flujo >> cadAuxiliar;
  5.     fecha = cadAuxiliar; // Si puedes usar std::string
  6.     fecha = cadAuxiliar.c_str(); // Si quieres seguir usando char*
  7.  
  8.     return flujo;
  9. }

Un saludo.
__________________
La ayuda se paga con esfuerzo o con dinero. Si no estás dispuesto a esforzarte y quieres que te hagan los deberes pide presupuesto, al menos así ahorrarás tiempo.
  #10 (permalink)  
Antiguo 19/04/2016, 07:20
Avatar de agusax  
Fecha de Ingreso: junio-2011
Ubicación: Puerto Real (Cádiz)
Mensajes: 74
Antigüedad: 13 años, 5 meses
Puntos: 3
Respuesta: Duda puntual: Cadenas de fechas

Era una exigencia del profesor.
Muchas gracias por su tiempo y ayudarme, voy a marcar el post como SOLUCIONADO.
__________________
"Nunca confíes en un ordenador que no puedas lanzar por una ventana" -- Steve Wozniak
"El software es como el sexo: mejor si es libre y gratis" -- Linus Torvalds

Etiquetas: cadena, cadenas, char, int, programa
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 11:41.