[C]Función SPLIT

Iniciado por Binary_Death, 29 Junio 2011, 19:57 PM

0 Miembros y 1 Visitante están viendo este tema.

Binary_Death

He hecho esta típica función en C...
Es digamos la primera versión así que debe de tener muchos errores, de hecho hasta me atrevería a decir que es cutre, pero en fin, aquí os la dejo:


/* char **split(char *string, char *sep);
   Coded by Binary_Death on 30/6/2011
*/
#include <stdlib.h>
#include <stdio.h>
char **split(char*,char*);
int _strlen(char*);
int _cmp(char*,char*,int);
int main() {
    char **array = split("STRING1#DLM#STRING2#DLM#STRING3","#DLM#");
    for(int y=0;y<3;y++) printf("%s\n", array[y]);
    getchar();
    return 0;
}
char **split(char *string,char *sep) {
     int str_len=_strlen(string);
     int sep_len=_strlen(sep);
     int ptr_block=0, chr=0, bool_end=0;
     char **buffer = (char**)malloc(sizeof(char*));
     *buffer = (char*)malloc(sizeof(char*));**buffer=0;
     char *tok = (char*)malloc(sep_len*sizeof(char));
     for(int z=0;z<str_len;z++) {
             for(int n=0;n<sep_len&&!bool_end;n++)
             {(str_len-(z+1)>=sep_len)?tok[n]=string[z+n]:bool_end=1;}
             if(_cmp(tok,sep,sep_len)||bool_end) {
                                  buffer[ptr_block][chr++] = string[z];
                                  buffer[ptr_block] = (char*)realloc(buffer[ptr_block],chr*sizeof(char*));
                                  buffer[ptr_block][chr] = 0;
                                   } else {
                                          buffer = (char**)realloc(buffer,(++ptr_block+1)*sizeof(char*));
                                          buffer[ptr_block] = (char*)malloc(sizeof(char*));
                                          chr=0;z+=sep_len-1;
                                   }                           
    }
free(tok);
return buffer;
}
int _strlen(char *pstr) {
    int i=0;
    while(*(pstr++)!='\0') i++;
    return i;
}
int _cmp(char *fstr,char *sstr, int len) {
    int bytes=0;
    while(bytes++<len) if(*(fstr++)!=*(sstr++)) return 1;
    return 0;
}


Agradecería que se me reportaran los errores y así mejorar  :P

Saludos!

EDITO: Ya esta arreglado! Igual seguro que tiene muchos errores más, ya se irán arreglando, yo soy paciente  ;D

EDITO2: Segunda modificación, he reducido y optimizado muchísimo el código.

BlackZeroX

#1
.
Lamento responder tan tarde.

Con respecto a los '\0' con bytes 0 esta clase SI los toma en cuenta. de hecho por eso la mejore ( relamente fue por que tenia que hacer un trabajo escolar donde tenia que tratar estos bytes y la verdad los strings se quedaban escasos ante esta problematica, ya que usan este '\0' como indicador de fin de cadena ).

Aqui te dejo la liga de la clase...

cls_Byte ( Funciones Binarias ) ByteReplace, ByteSplit, ByteMid, ByteExits...
* Esta puede diferenciar mayusculas de minusculas segun se le indique...
* Se le puede limitar en la Cantidad X a cortar.
* Toma enconsideracion TODOS los bytes dentro de un Rango dado ( segun la longitud ) es decir que tengan lo que tengan lo Tomara en cuenta HASTA EL FINAL.

Dulces Lunas!¡.
.
The Dark Shadow is my passion.

Binary_Death

#2
Recién ahora me di cuenta de un error que no sé de donde viene... ando ahí intentando descubrir  :silbar:

Si intento con una cadena como:

"String1SEPAString1","SEPA"

Curiosamente, al imprimir array[1] sólo me muestra String, en vez de String1.
Y por cada carácter que aumento en el separador, un carácter menos que muestra de la String...

Gracias por los links, les echaré una leída  :P


EDIT: Ya le vi el error... miraré la mejor forma de corregirlo y lo edito en el primer post.

Una pregunta, BlackZeroX, ¿tú función es capaz de interpretar cadenas con un carácter nulo '\0' en medio? Es que sería necesario si se usa la función con ficheros binarios, y no sé como hacer que eso sea posible.

Binary_Death

Aquí dejo la versión casi completa, hasta reporte de nuevos fallos.


/* char **split(char *string, char *sep);
   Coded by Binary_Death on 30/6/2011
*/
#include <stdlib.h>
#include <stdio.h>
typedef struct {
        char **substring_ptr;
        int number_of_substrings;
} split_struct;
split_struct* split(char*,char*);
int _strlen(char*);
int _cmp(char*,char*,int);
int main() {
    split_struct *str;
    str = split("STRING1#DLM#STRING2#DLM#STRING3","#DLM#");
    for(int y=0;y<str->number_of_substrings;y++)
    {printf("%s\n", str->substring_ptr[y]);}
    getchar();
    return 0;
}
split_struct *split(char *string,char *sep) {
     split_struct *retvalue;
     retvalue = (split_struct*)malloc(sizeof(split_struct));
     int str_len=_strlen(string);
     int sep_len=_strlen(sep);
     int ptr_block=0, chr=0, bool_end=0;
     char **buffer = (char**)malloc(sizeof(char*));
     *buffer = (char*)malloc(sizeof(char*));**buffer=0;
     char *tok = (char*)malloc(sep_len*sizeof(char));
     for(int z=0;z<str_len;z++) {
             for(int n=0;n<sep_len&&!bool_end;n++)
             tok[n]=(z+n<str_len)?string[z+n]:bool_end=1;
             if(_cmp(tok,sep,sep_len)||bool_end) {
                                  buffer[ptr_block][chr++] = string[z];
                                  buffer[ptr_block] = (char*)realloc(buffer[ptr_block],chr*sizeof(char*));
                                  buffer[ptr_block][chr] = 0;
                                   } else {
                                          buffer = (char**)realloc(buffer,(++ptr_block+1)*sizeof(char*));
                                          buffer[ptr_block] = (char*)malloc(sizeof(char*));**(buffer+ptr_block)=0;
                                          chr=0;z+=sep_len-1;
                                   }                           
    }
free(tok);
retvalue->substring_ptr = buffer;
retvalue->number_of_substrings = ptr_block+1;
return retvalue;
}
int _strlen(char *pstr) {
    int i=0;
    while(*(pstr++)!='\0') i++;
    return i;
}
int _cmp(char *fstr,char *sstr, int len) {
    int bytes=0;
    while(bytes++<len) if(*(fstr++)!=*(sstr++)) return 1;
    return 0;
}


Esta vez devuelve un puntero a una estructura que contiene el array de cadenas y el número de cadenas obtenidas.

Saludos!

BlackZeroX

.
Lamento responder tan tarde.

Con respecto a los '\0' con bytes 0 esta clase SI los toma en cuenta. de hecho por eso la mejore ( relamente fue por que tenia que hacer un trabajo escolar donde tenia que tratar estos bytes y la verdad los strings se quedaban escasos ante esta problematica, ya que usan este '\0' como indicador de fin de cadena ).

Aqui te dejo la liga de la clase...

cls_Byte ( Funciones Binarias ) ByteReplace, ByteSplit, ByteMid, ByteExits...
* Esta puede diferenciar mayusculas de minusculas segun se le indique...
* Se le puede limitar en la Cantidad X a cortar.
* Toma enconsideracion TODOS los bytes dentro de un Rango dado ( segun la longitud ) es decir que tengan lo que tengan lo Tomara en cuenta HASTA EL FINAL.

Dulces Lunas!¡.
.
The Dark Shadow is my passion.

rir3760

La función "split" del programa de Binary_Death se puede mejorar.

Se debería eliminar la llamada a "getchar" al final de la función "main" ya que la generación de una pausa de forma automática es problema del IDE, no del programa.

Y ya que la función retorna una única estructura no es necesario reservar memoria para ella, puede declararse una dentro de la funcion y utilizarla como valor de retorno.

También se pueden eliminar todas las conversiones explicitas ya que en C no son necesarias, "sizeof(char)" también hay que eliminarlo ya que este siempre es igual a uno.

----

Otra forma de realizar la operación utilizando la función strstr y aritmética de punteros es:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **split(char const *linea, char const *sep);

int main(void)
{
   char **p;
   char **q;
   
   p = split("STRING1#DLM#STRING2#DLM#STRING3", "#DLM#");
   
   for (q = p; *q != NULL; q++){
      puts(*q);
      free(*q);
   }
   free(p);
   
   return EXIT_SUCCESS;
}

char **split(char const *linea, char const *sep)
{
   char **p;
   char const *a;
   char const *b;
   int i;
   
   p = malloc((strlen(linea) / 2 + 2) * sizeof *p);
   
   i = 0;
   a = linea;
   while ((b = strstr(a, sep)) != NULL){
      if (b != a){
         p[i] = malloc(b - a + 1);
         strncpy(p[i], a, b - a);
         i++;
      }
     
      a = b + strlen(sep);
   }
   if (*a != '\0'){
      p[i] = malloc(strlen(a) + 1);
      strcpy(p[i], a);
      i++;
   }
   p[i++] = NULL;
   
   p = realloc(p, i * sizeof *p);
   return p;
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Khronos14

Binary_Death, sólo una cosa: ver tu función split me dió un dolor de cabeza que no te lo puedes imaginar, de hecho pasé de mirarla.

Tienes que aprender a programar código ordenado y hacerlo agradable a la vista, no hay color entre tu función y la que puso rir3760.

Saludos.

Binary_Death


Sí, verdaderamente es un lío esa función... tengo que hacer las cosas más agradables a la vista, aunque por costumbre tiendo a hacerlas así.

Con strstr queda fácil  ;D pero pensé que la gracia era hacer una sin contar con ninguna función de string.h.

Tal vez la rehaga y la vuelva a subir, esta vez mucho más legible.

Un saludo, y muchas gracias por comentar. Nos vemos.