Universidad de Costa Rica
|
|
config
para archivos de configuración de programas
; bt0pp.cfg ; ========= ext=txt pdf doc docx odt htm html url xls ods jpg png gif ppt odp general=curriculum horario|horas declaracion gsigla=??#### ;??-### ;???### ;etc. gid=g## guno=nota|notas asistencia evaluacion carta|descripcion gsec=##-tarea|##-tpg examen.ex# (enunciado mejor peor) ;proyecto-# ;lab|laboratorio## |
La clase config
permite almacenar los valores de
configuración para un programa. Estos valores se toman de
un archivo de texto que contiente parejas de la forma
llave=valor
en donde la palabra llave está
compuesta de letras, números y los caracteres '-
'
y '_'
. Ejemplos de llaves válidas son
los siguientes: { "SIN"
"CON_12"
"R-LOCO"
}. Los valores son un poco más
estructurados, porque permite usar patrones como
"###"
para representas todos los números desde
"000"
hasta "999"
o "??"
para todas las combinaciones de 2 caracteres en los también
que se incluye desde "aa"
hasta "zz"
y
desde "AA"
hasta "ZZ"
, pues nunca se
considera diferente una letra mayúsculas de su
corresponiente minúscula. Además, los valores pueden
tener alternativas, como "nota|notas|n"
y
también pueden contener repetidores entre
paréntesis, que aparecen separados por un espacio en blanco
como en "(txt pdf htm html)"
. El caracter
';'
sirve para marcar el comienzo de un comentario,
que termina hasta el final del renglón. Otro ejemplode un
archivo de configuración cuyos valores pueden ser
almacenados en una instancia de la clase config
:
; TODO esto es un comentario llave=valor ; valor puede ser simple SIN=??#### ; CI0099 y con --0700 calzan en este patrón CON_12=#12 ; 112 y 812 sí calzan pero 0012 no calza otro=alfa|beta ; patrón que solo calza con alfa y con beta ; R-LOCO=???(txt pdf htm html) ; calza con aaa(txt txt pdf pdf) ; NO es posible usar ninguno de { '?' '|' ';' '#' '(' ')' } en "llave" en "valor" |
Para implementar su clase haga un programa de prueba que permita
leer un archivo de texto que contiene el valor que será
almacenado en su clase config
. Talvez le sirva usar
la versión de la función
getline()
que retornar una hilera estándar, de tipo
std::string<>
,
pero no olvide incluir ejemplos
BUnit en las
especificaciones.
BUnit.h
: Un módulo simple para aprender prueba unitaria de programas en C++,
X Simposio Internacional de Informática Educativa
(SIIE'08)
realizado del 1 al 3 de octubre 2008, Salamanca, España,
I.S.B.N.: 978-84-7800-312-9, pp425-430, octubre 2008.
http://www.di-mare.com/adolfo/p/BUnit.htm
En la documentación de su clase incluya una
comparación con el formato
.ini
que se ha usado en Windows para almacenar la configuración de los programas.
config
necesito redefinir muchos de los métodos del diccionario. Me parece que eso da mucha duplicación y quisiera saber si puedo poner el
Rep público para no tener que reprogramar todo, hasta los iteradores. ¿Puedo hacerlo solo esta vez?
class valor_t { /* ... */ }; class config : public std::map< std::string, std::list<valor_t> > { public: typedef std::string llave_t; typedef std::list< valor_t > lista_de_valores_t; typedef std::pair< llave_t , lista_de_valores_t > renglon_t; };
valor_t
esté definido dentro de la clase config
, ahora es necesario dejarlo fuera de esa clase.
config
? Es que me parece que hay algunos renglones que vienen con errores, como por ejemplo los siguientes:
;config con montones de repeticiones de "gsec" gsec= ; llave sin palabras = w ; palabras sin llave gsec= ) algo ; paréntesis abierto de primero gsec= | algo ; barrita de primera gsec= (solo) ; solo una palabra en el repetidor gsec= solo| ; barrita sin segunda palabra gsec= ((si o no)); doble paréntesis
std::map<>
esa clase se encarga de nunca almacenar 2 renglones con la misma llave, por lo que solo el primero de todos los renglones con llave "gsec"
quedaría almacenado en el dicciconario: en este caso lo mejor es agregar estos parámetros nuevos a la llave que ya está en el diccionario. Para los demás errores basta retornar un código de error al analizar el renglón independientemente de los otros renglones (es más simple solo detectar el primero error). Además, no se vale poner paréntesis o barritas anidadadas (para eso es mejor almacenar la configuración en formato
XML).
config
, ¿le parece si lo imprimmos con las 3 catergorías? Por ejemplo los siguientes:
; CONFIG.cfg guno = nota|notas asistencia evaluacion examen (texto mejor peor) gotro = nota notas asistencia evaluacion examen texto mejor peor
X:\DIR\SubDir> use_config.exe CONFIG.cfg use_config.exe ==> Leyendo archivo CONFIG.cfg... Estas son las llaves y sus valores Llave [guno] - Palabras: asistencia evaluacion examen - Alternativos: | nota notas | - Repetidores: ( texto mejor peor ) Llave [gotro] - Palabras: nota notas asistencia evaluacion examen texto mejor peor - Alternativos: - Repeditores:
use_config.cpp
genera, pero me gustaría que ese programa verifique que un repetidor aparece únicamente después de una palabra. Por ejemplo, en la llave "guno"
los repetidores "(texto mejor peor)"
se aplican a la palabra "examen"
que es la que les antecede y, por eso, el programa debiera destacare este hecho al producir algo similar a lo siguiente:
X:\DIR\SubDir> use_config.exe CONFIG.cfg use_config.exe ==> Leyendo archivo CONFIG.cfg... Estas son las llaves y sus valores Llave [guno] - Palabras: asistencia evaluacion - Alternativos: | nota notas | - Repetidores: examen ( texto mejor peor ) Llave [gotro] - Palabras: nota notas asistencia evaluacion examen texto mejor peor - Alternativos: - Repeditores:
; CONFIG.cfg guno = nota|notas asistencia evaluacion examen (texto mejor peor) gotro = nota notas asistencia evaluacion examen texto mejor peor
valor_t
me complica todo porque creo que es más fácil solo usar una lista de hileras en el diccionario. Yo lo que quisiera es meter las hileras poniendo entre barritas los valores alternativos y entre paréntesis los repeditores. ¿Tengo que usar su clase config
o puedo usar la mía? Por ejemplo, el renglón:
guno = nota|notas asistencia evaluacion examen (texto mejor peor)
[guno]
queda asociada a:
[|] [nota] [notas] [|] [asistencia] [evaluacion] [examen] [(] [texto] [mejor] [peor] [)]
class valor_t { /* ... */ }; class config : public std::map< std::string, std::list< std::string > > { public: typedef std::string llave_t; typedef std::list< std::string > lista_de_valores_t; typedef std::pair< llave_t , lista_de_valores_t > renglon_t; };
bool check_ok(const valor_t& r);
porque una hilera puede tener cualquier valor y no por eso es válido o inválido ese valor. Además, si la hilera contiene una palabra no es posible saber si después viene un paréntesis para que sea repetidora.valor_t
sea una clase derivada de la hilera estándar, pero tenés razón en cuanto a que la noción de posición se pierde en la hilera. Una forma de remediar esto es trabajar con los iteradores de la lista de hileras que está asociada a cada llave:
class valor_t : public std::string { public: // etc... }; class config : public std::map< std::string, std::list< valor_t > > { public: // etc... bool esBarrita( lista_de_valores_t::const_iterator it ) const { if ( this->end() == it ) { return false; } return (*it=="|"); } bool esRepetidor( lista_de_valores_t::const_iterator it ) const { if ( esBarrita(it) } { return false; } lista_de_valores_t::const_iterator itNext = it; itNext++; if ( this->end() == itNext ) { return false; } return (*it=="("); } typedef std::string llave_t; typedef std::list< valor_t > lista_de_valores_t; typedef std::pair< llave_t , lista_de_valores_t > renglon_t; // etc... friend bool check_ok( const config& c ); friend bool check_ok( const renglon_t& r ); bool check_ok( const lista_de_valores_t::const_iterator& it ); };
Entregue su tarea por correo electrónico, como lo hizo anteriormente.
Tiempo de entrega: | 7 días |
|
|
Segunda etapa: | 3 días | ||
Modalidad: | En parejas |
Adolfo Di Mare <adolfo@di-mare.com>.
|