cadena de caracteres dividida con delimitador de varios caracteres en C

6 minutos de lectura

cadena de caracteres dividida con delimitador de varios caracteres en
Sadia Bashir

quiero dividir un char *string basado en un delimitador de múltiples caracteres. Yo sé eso strtok() se usa para dividir una cadena, pero funciona con un delimitador de un solo carácter.

Quiero dividir char *string en función de una subcadena como "abc" o cualquier otra subcadena. ¿Cómo se puede lograr eso?

  • posible duplicado de ¿Cómo extraer la cadena si tenemos más de un delimitador?

    – Jongware

    22 de abril de 2015 a las 6:35

  • Tengo una consulta más, ¿cómo puedo comparar este valor str en una declaración if? por ejemplo, si tengo char *str = “abc” y obtuve un valor de subcadena de una cadena larga y quiero comparar este valor de subcadena con *str: if(str == substr)

    – Sadia Bashir

    22 de abril de 2015 a las 7:40

  • ¡Entendido, strcmp se usa para este propósito! ¡Gracias de nuevo a todos!

    – Sadia Bashir

    22 de abril de 2015 a las 7:46

Encontrar el punto en el que se produce la secuencia deseada es bastante fácil: strstr apoya que:

char str[] = "this is abc a big abc input string abc to split up";
char *pos = strstr(str, "abc");

Entonces, en ese punto, pos apunta a la primera ubicación de abc en la cadena más grande. Aquí es donde las cosas se ponen un poco feas. strtok tiene un diseño desagradable en el que 1) modifica la cadena original y 2) almacena un puntero a la ubicación “actual” en la cadena internamente.

Si no nos importara hacer más o menos lo mismo, podríamos hacer algo como esto:

char *multi_tok(char *input, char *delimiter) {
    static char *string;
    if (input != NULL)
        string = input;

    if (string == NULL)
        return string;

    char *end = strstr(string, delimiter);
    if (end == NULL) {
        char *temp = string;
        string = NULL;
        return temp;
    }

    char *temp = string;

    *end = '\0';
    string = end + strlen(delimiter);
    return temp;
}

Esto funciona. Por ejemplo:

int main() {
    char input [] = "this is abc a big abc input string abc to split up";

    char *token = multi_tok(input, "abc");

    while (token != NULL) {
        printf("%s\n", token);
        token = multi_tok(NULL, "abc");
    }
}

produce aproximadamente la salida esperada:

this is
 a big
 input string
 to split up

No obstante, es torpe, difícil de hacer seguro para subprocesos (tienes que hacer que su interior string hilo variable local) y, en general, solo un diseño de mierda. Usando (por ejemplo) una interfaz algo así como strtok_rpodemos solucionar al menos el problema de seguridad de subprocesos:

typedef char *multi_tok_t;

char *multi_tok(char *input, multi_tok_t *string, char *delimiter) {
    if (input != NULL)
        *string = input;

    if (*string == NULL)
        return *string;

    char *end = strstr(*string, delimiter);
    if (end == NULL) {
        char *temp = *string;
        *string = NULL;
        return temp;
    }

    char *temp = *string;

    *end = '\0';
    *string = end + strlen(delimiter);
    return temp;
}

multi_tok_t init() { return NULL; }

int main() {
    multi_tok_t s=init();

    char input [] = "this is abc a big abc input string abc to split up";

    char *token = multi_tok(input, &s, "abc");

    while (token != NULL) {
        printf("%s\n", token);
        token = multi_tok(NULL, &s, "abc");
    }
}

Sin embargo, supongo que lo dejaré así por ahora: para obtener una interfaz realmente limpia, realmente queremos reinventar algo como las corrutinas, y eso probablemente sea demasiado para publicar aquí.

  • ¿Cómo se adoptaría esto para hacer lo mismo con un puntero de cadena LPSTR? Sé que puedo reemplazar todas las funciones de cadenas nativas con sus equivalentes de puntero lejano (_fstrlen, etc.), pero la entrada y la salida deben ser cadenas LPSTR.

    – Tobías Timpe

    16 de febrero de 2021 a las 22:12

  • @TobiasTimpe: LPSTR es solo un alias para char *.

    – Jerry Ataúd

    16 de febrero de 2021 a las 22:18


  • Sí, pero estoy trabajando en Win16 con LPSTR que en realidad es un puntero lejano y realmente no puedo convertir la entrada en una matriz de caracteres normal porque sería demasiado grande.

    – Tobías Timpe

    16 de febrero de 2021 a las 22:28

  • @TobiasTimpe: la equivalencia funciona principalmente en ambas direcciones, por lo que si cambia todas las instancias de char * en este código para LPSTRprobablemente esté bastante cerca de que funcione (pero no he tenido instalado un SDK de Win16 durante años, así que no puedo probarlo).

    – Jerry Ataúd

    16 de febrero de 2021 a las 23:40

cadena de caracteres dividida con delimitador de varios caracteres en
Sourav Ghosh

Puedes escribir fácilmente tu propio analizador usando strstr() para lograr lo mismo. El algoritmo básico puede verse así

  • utilizar strstr() para encontrar la primera aparición de toda la cadena delimitadora
  • marcar el índice
  • copie desde el inicio hasta el índice marcado, ese será su token esperado.
  • para analizar la entrada de las entradas posteriores, ajuste la clasificación de la cadena inicial para avanzar por la longitud del token + la longitud de la cadena delimitadora.

1647630668 330 cadena de caracteres dividida con delimitador de varios caracteres en
Santhosh Pai

EDITAR: Consideró las sugerencias de Alan y Sourav y escribió un código básico para el mismo.

#include <stdio.h>

#include <string.h>

int main (void)
{
  char str[] = "This is abc test abc string";

  char* in = str;
  char *delim = "abc";
  char *token;

  do {

    token = strstr(in,delim);

    if (token) 
      *token = '\0';

    printf("%s\n",in);

    in = token+strlen(delim);

  }while(token!=NULL);


  return 0;
}

  • Tienes mucha razón, pero creo que eso no es lo que OP quiere. él quiere considerar "abc" como un único delimitador.:-)

    – Sourav Ghosh

    22 de abril de 2015 a las 6:09

  • Eso está bien, pero la primera parte de su respuesta puede ser engañosa. Considere eliminar eso. 🙂

    – Sourav Ghosh

    22 de abril de 2015 a las 6:24

  • Tampoco creas que la segunda solución funcionará. strsep no busca solo “abc”. Busca cualquier permutación de los caracteres en “abc”. Pruebe esta cadena en su programa como ejemplo: “Esta es una cadena ac de prueba bac”. Probablemente necesite usar strstr en lugar de.

    – Kaylum

    22 de abril de 2015 a las 6:24


  • @AlanAu [Just to add my two cents] …y strsep() no es C estándar, en mi humilde opinión.

    – Sourav Ghosh

    22 de abril de 2015 a las 6:36

  • @AlanAu: He implementado la lógica usando strstr, gracias por las entradas.

    – Santhosh Pai

    22 de abril de 2015 a las 7:09

Escribí una implementación simple que es segura para subprocesos:

struct split_string {
    int len;
    char** str;
};
typedef struct split_string splitstr;
splitstr* split(char* string, char* delimiter) {
    int targetsize = 0;
    splitstr* ret = malloc(sizeof(splitstr));
    if (ret == NULL)
        return NULL;
    ret->str = NULL;
    ret->len = 0;
    char* pos;
    char* oldpos = string;
    int newsize;
    int dlen = strlen(delimiter);
    do {
        pos = strstr(oldpos, delimiter);
        if (pos) {
            newsize = pos - oldpos;
        } else {
            newsize = strlen(oldpos);
        }
        char* newstr = malloc(sizeof(char) * (newsize + 1));
        strncpy(newstr, oldpos, newsize);
        newstr[newsize] = '\0';
        oldpos = pos + dlen;
        ret->str = realloc(ret->str, (targetsize+1) * sizeof(char*));
        ret->str[targetsize++] = newstr;
        ret->len++;
    } while (pos != NULL);
    return ret;
}

Usar:

splitstr* ret = split(contents, "\n");
for (int i = 0; i < ret->len; i++) {
    printf("Element %d: %s\n", i, ret->str[i]);
}

1647630669 716 cadena de caracteres dividida con delimitador de varios caracteres en
Charley Wu

un modificado strsep implementación que admite delimitador de varios bytes

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**
 * Split a string into tokens
 * 
 * @in: The string to be searched
 * @delim: The string to search for as a delimiter
 */
char *strsep_m(char **in, const char *delim) {
  char *token = *in;

  if (token == NULL)
    return NULL;
    
  char *end = strstr(token, delim);
  
  if (end) {
    *end = '\0';
    end += strlen(delim);
  }
  
  *in = end;
  return token;
}

int main() {
  char input[] = "a##b##c";
  char delim[] = "##";
  char *token = NULL;
  char *cin = (char*)input;
  while ((token = strsep_m(&cin, delim)) != NULL) {
    printf("%s\n", token);
  }
}

  • a diferencia de strtok()el código producirá 3 tokens para "##foo##"que puede o no esperarse.

    – chqrlie

    6 de marzo a las 13:35


  • a diferencia de strtok()el código producirá 3 tokens para "##foo##"que puede o no esperarse.

    – chqrlie

    6 de marzo a las 13:35


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad