Hola, estoy haciendo un programita que parsea unos templates en base a un .csv y genera unos archivos de texto. Por ejemplo:
Si mi .csv es:
"hola#mundo#alegría"
y mi template es:
"[$1] [$2] hoy estoy lleno de [$3]"
el resultado seria:
"hola mundo hoy estoy lleno de alegría"
Mi problema es como encarar el procesamiento de los tokens. Bien yo podría encarar dos soluciones:
1) Hacerlo con un bucle while ((c=fgetc(archivo))!=EOF) y dentro preguntar si me tope con un '[', luego con un '$', luego con un numero y luego con un ']'. Esto claramente es una chanchada.
2) Otra solución seria leer el contenido del archivo de a trozos almacenandolo en un char* y luego usar alguna de las funciones de la librería string.h para encontrar mi token y reemplazarlo. Esta opción es mas prolija, pero si se diera que elegí leer de a 100 caracteres y en el 99vo carácter esta el carácter '[', y luego al principio del próximo string esta "$3] y ese día blablabla....". No me parsearia correctamente el token, ¡se lo saltearía!.
¿Se les ocurre una solución mejor?
Saludos y gracias por detenerse a leer.
Hola! creo q mejores soluciones a las q das vos no hay(o al menos no se me ocurre en este momento)... Lo que podes hacer es usar strstr para saber cuando hay un "[$" en la cadena y strtok para separar en tokens el .csv. Igual creo que el gran problema es generar la cadena final "hola mundo hoy estoy lleno de alegría", ya q por lo que veo vas a necesitar un buen manejo de punteros
Saludos
PD: strtok y strstr ambas funciones de string.h
¡Buenas!
Tienes otra solucion posible. Leer el tamaño del fichero con los parametros, asignar dinamicamente memoria para almacenar los datos y leer el bloque entero del fichero. Haces lo mismo con el fichero en el que va a haber sustituciones, y ya te olvidas de cadenas que pueden estar o no cortadas. Luego como bien te han dicho, con strchr, strstr y strtok te vas apañando.
¡Saludos!
Ammm te cree el código ya que no tengo nada que hacer... malditas vacaciones.
crea un archivo llamado "c:\a.txt" y dentro escribe las palabras separadas con espacios...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PARSETHIS "[$2] [$2] [$3] [$4] [$300] [$030]"
typedef struct acumstrings
{
char **ptr;
size_t count;
} acumstrings;
acumstrings acum;
inline const char* getTokenIndex(const char *str, long *Index)
{
if (!str) return NULL;
char *ptr = strstr(str, "[$");
char *end = NULL;
if (ptr) {
ptr += strlen("[$");
(*Index) = strtol(ptr, &end, 10);
}
return ptr;
}
inline char* replace(const char *str, const char *find, const char *rep)
{
char *ret = NULL;
size_t strOln;
size_t strFln;
size_t strRln;
const char *end[2];
size_t sizeL;
size_t sizeR;
if (!str) return NULL;
strOln = strlen(str);
if (!find || (end[0] = strstr(str, find)) == NULL) {
ret = (char*)malloc(strOln + 1);
memcpy(ret, str, strOln + 1);
return ret;
}
strRln = strlen(rep);
strFln = strlen(find);
end[1] = (char*)((size_t)end[0] + strFln);
sizeL = (size_t)end[0] - (size_t)str;
sizeR = ((size_t)str + strOln) - (size_t)end[1];
ret = (char*)malloc(sizeL + strRln + sizeR + 1);
memcpy(ret, str, sizeL);
memcpy((void*)((int)ret + sizeL), rep, strRln);
memcpy((void*)((int)ret + sizeL + strRln), end[1], sizeR);
ret[sizeL + strRln + sizeR] = '\0';
return ret;
}
int main ()
{
FILE* file;
size_t ret;
char* strLast = NULL;
char* strNew = NULL;
char* strNewFind = NULL;
char strToken[20];
long index;
file = fopen("C:\\a.txt", "rb+");
// Obtenemos cada palabra.
while (!feof(file))
{
acum.ptr = (char**)realloc(acum.ptr, (acum.count + 1) * sizeof(char**));
acum.ptr[acum.count] = (char*)calloc(256, 1);
ret = fscanf(file, "%s", acum.ptr[acum.count]);
puts(acum.ptr[acum.count]);
++acum.count;
}
fclose(file);
strNew = (char*)malloc(strlen(PARSETHIS) + 1);
strcpy(strNew, PARSETHIS);
strNewFind = strNew;
// reemplazamos cada token por cada una de las palabras respectivas.
while(strNewFind = getTokenIndex(strNewFind, &index))
{
sprintf(strToken, "[%$%d]\0", index);
if (acum.count > index) {
strLast = strNew;
strNew = replace(strLast, strToken, acum.ptr[index - 1]);
free(strLast);
strNewFind = strNew;
} else {
++strNewFind;
}
}
while(acum.count--)
free(acum.ptr[acum.count]);
free(acum.ptr);
puts(strNew);
free(strNew);
getchar();
return 0;
}
Dulces Lunas!¡.
Buenisimo, muchas gracias Black, tu solución me sirvió bastante para darme una idea.
Saludos!
Ejem ... no era más fácil leer línea a línea (no se agarren la *mala* costumbre de leer todo de un saque), pasar todo por strtok() (http://pubs.opengroup.org/onlinepubs/009695399/functions/strtok.html) y tomar los 3 valores y encajarlos en un printf como el ejercicio lo pide?
Saludos.
Hola! una pregunta BlackZeroX (Astaroth) ¿el codigo q hiciste es en C no?? si es asi podrias explicarme cual es la funcion de inline?? que no lo conocia
Saludos
Cita de: vertexSymphony en 28 Junio 2012, 09:14 AM
Ejem ... no era más fácil leer línea a línea (no se agarren la *mala* costumbre de leer todo de un saque), pasar todo por strtok() (http://pubs.opengroup.org/onlinepubs/009695399/functions/strtok.html) y tomar los 3 valores y encajarlos en un printf como el ejercicio lo pide?
Saludos.
Gracias por ilustrarme vertex, heló aquí el código.
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int main()
{
char * tokens[] = {"cosas","hacerlas"};
char s1[] = "Las [$0] hay que [$1] en el momento que hay que [$1].\n";
char s2[] = "[$";
char *ptr;
ptr = strtok( s1, s2 ); // Primera llamada => Primer token
if ( (isdigit(ptr[0])) && (ptr[1] == ']') ) {
//Es un token
printf("%s%s", tokens[atoi(ptr)], ptr+2);
} else {
printf("%s",ptr);
}
while( (ptr = strtok( NULL, s2 )) != NULL ) // Posteriores llamadas
if ( (isdigit(ptr[0])) && (ptr[1] == ']') ) {
//Es un token
printf("%s%s", tokens[atoi(ptr)], ptr+2);
} else {
printf("%s",ptr);
}
return 0;
}
Saludos
En mi parecer, al ser un forma de ver el formato de manera uniforme y repetitiva (no compuesto/compleja) donde cada palabra (no consideran frases) esta solo separada por un signo (en mi caso no era # si no mas bien el espacio o salto de linea '\n' o cualquier carácter que tenga el mismo uso) funciona bastante bien fscanf(file, "%s", ...),se cargan todas la palabras en un "Buffer" para no estar re-leyendo a cada instante el archivo y evitar la latencia de acceso al disco duro por ello yo descarte el uso de strtok() y de lectura de lineas las cuales desconozco su longitud.
* Cuando es un formato del este estilo (palabra1 palabra2 palabra3 palabra4 ... palabraN-esima) y no hay formatos complejos fscanf(file, "%s", ...) va perfecto siempre y cuando haya un separador de palabra, de lo contrario es mas recomendable cargar el archivo en memoria y proseguir a identificar cada palabra/signo clave.
por ejemplo ( Yo cargaría en memoria el archivo si estuviera en el disco y aplicar un analizador sintáctico y enviar todo el archivo a estructuras obviamente ya analizado, a su vez también evitar la mayor cantidad de ciclos incluyendo strtok() ya que en este tipo de cuestiones se pueden omitir o tener palabras/signos opcionales y strtok() sacrificaría demasiado el redimiendo de un algoritmo ademas que ignoraria palabras entre el punto inicial y el punto final, es decir funcionaria solo para identificar la existencia en este caso ):
// este es un comentario
cadena1{ // Note que no hay espacio entre la palabra y {
casena(propiedad1 = "algo") { // Note que la palabra tiene propiedades; Note que hay un espacio antes del {
item1 = ""
}
}
* strtok() esta bien para hacer por ejemplo una función que extraiga un trozo de texto o similares pero para analizar formatos() puede que si y puede que no, en mi criterio es dar muchos vueltas (en formatos complejos) en simples como este no hay bronca pero lo mejor es leer el archivo y meterlo en estructuras que representen al archivo original y así evitar la latencia de acceso al disco duro.
NOTA: la caga en memoria seria por bloques mas no todo de golpe.
Dulces Lunas!¡.