Necesito una mezcla de strtok y strtok_single

7 minutos de lectura

Necesito una mezcla de strtok y strtok single
aVC

Tengo la siguiente cadena que estoy tratando de analizar en busca de variables.

char data[]="to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards."

Empecé con strtok y el siguiente código

char *to=parsePostData("to",data);

char* parsePostData(char s[],char t[])
{
  char *postVal;
  char *pch;
  char tCpy[512];//Make a copy. Otherwise, strtok works on the char pointer, and original char array gets modified/ corrupted.
  strcpy(tCpy,t);
  pch = strtok (tCpy,"=&");
  while (pch != NULL)
  {
      if(strcmp(pch,s)==0) {
            pch= strtok (NULL, "&");
                return pch;          
      }else{
        pch = strtok (NULL, "=&");  
      }
  }      
}

Esto funciona bien, excepto cuando se trata de delimitadores consecutivos como el que está después de “título”. Así que encontré esta implementación personalizada de strtok_single. Necesita saber cuándo no aparecen datos entre dos separadores de tokens usando strtok()

char * strtok_single (char * str, char const * delims)
{
  static char  * src = NULL;
  char  *  p,  * ret = 0;

  if (str != NULL)
    src = str;

  if (src == NULL)
    return NULL;

  if ((p = strpbrk (src, delims)) != NULL) {
    *p  = 0;
    ret = src;
    src = ++p;
  }

  return ret;
}

Pero con esto, el problema es que no puedo obtener “firma”, ya que no hay un delimitador & después de eso.

¿Cómo puedo obtener una combinación de estos dos, para no perderme la última variable y poder manejar delimitadores consecutivos?

  • Tal vez mire stackoverflow.com/questions/16807188/strtok-analogue-in-c?rq=1. Esto se dividirá en “=&” y “&” en una sola pasada, aunque supongo que obtendrá un falso espacio en blanco en “=&”, si entiendo lo que están haciendo correctamente.

    – mtrw

    18 de mayo de 2015 a las 2:14


  • @mtrw Estoy trabajando en arduino IDE. Si es posible, me gustaría no agregar más bibliotecas por cuestiones de tamaño del programa. Espero que haya una manera de modificar el código anterior para obtener el resultado, pero si no, buscaré el método que sugirió.

    – aVC

    18 de mayo de 2015 a las 2:21

  • @Cicada Estoy usando Arduino IDE y soy un principiante. Creo que usa C,C++ stackoverflow.com/a/11813275/903978

    – aVC

    18 de mayo de 2015 a las 2:29


  • @ Cicada, C sería mejor. Gracias 🙂

    – aVC

    18 de mayo de 2015 a las 2:36

  • Usé este y me funciona. stackoverflow.com/a/3375658/903978

    – aVC

    18 de mayo de 2015 a las 3:26

Necesito una mezcla de strtok y strtok single
jonathan leffler

Hay dos errores al acecho aquí. uno está en strtok_single(). Si lo ejecuta repetidamente, no devuelve el último segmento, después del = después de la firma, a diferencia strtok().

Cuando eso se solucione, todavía hay un problema con el código en parsePostData(); devuelve un puntero a una variable automática. La copia de la cadena debe manejarse de manera diferente; la forma más sencilla (que es coherente con el uso strtok() en vez de strtok_r() o strtok_s()) es hacer la tCpy estática variable.

Programa de prueba emt.c

Este es un programa compuesto que muestra los problemas y también un conjunto de correcciones. Aplica diferentes funciones ‘divisoras’, funciones con la misma firma que strtok() — a los datos. Demuestra el error en strtok_single() y eso strtok_fixed() corrige ese error. Demuestra que el código en parsePostData() funciona correctamente cuando está arreglado y strtok_fixed() se usa

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

/* Function pointer for strtok, strtok_single, strtok_fixed */
typedef char *(*Splitter)(char *str, const char *delims);

/* strtok_single - as quoted in SO 30294129 (from SO 8705844) */
static char *strtok_single(char *str, char const *delims)
{
    static char  *src = NULL;
    char  *p,  *ret = 0;

    if (str != NULL)
        src = str;

    if (src == NULL)
        return NULL;

    if ((p = strpbrk(src, delims)) != NULL)
    {
        *p  = 0;
        ret = src;
        src = ++p;
    }

    return ret;
}

/* strtok_fixed - fixed variation of strtok_single */
static char *strtok_fixed(char *str, char const *delims)
{
    static char  *src = NULL;
    char  *p,  *ret = 0;

    if (str != NULL)
        src = str;

    if (src == NULL || *src == '\0')    // Fix 1
        return NULL;

    ret = src;                          // Fix 2
    if ((p = strpbrk(src, delims)) != NULL)
    {
        *p  = 0;
        //ret = src;                    // Unnecessary
        src = ++p;
    }
    else
        src += strlen(src);

    return ret;
}

/* Raw test of splitter functions */
static void parsePostData1(const char *s, const char *t, Splitter splitter)
{
    static char tCpy[512];
    strcpy(tCpy, t);
    char *pch = splitter(tCpy, "=&");
    while (pch != NULL)
    {
        printf("  [%s]\n", pch);
        if (strcmp(pch, s) == 0)
            printf("matches %s\n", s);
        pch = splitter(NULL, "=&");
    }
}

/* Fixed version of parsePostData() from SO 30294129 */
static char *parsePostData2(const char *s, const char *t, Splitter splitter)
{
    static char tCpy[512];
    strcpy(tCpy, t);
    char *pch = splitter(tCpy, "=&");
    while (pch != NULL)
    {
        if (strcmp(pch, s) == 0)
        {
            pch = splitter(NULL, "&");
            return pch;
        }
        else
        {
            pch = splitter(NULL, "=&");
        }
    }
    return NULL;
}

/* Composite test program */
int main(void)
{
    char data[] = "to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards.";
    char *tags[] = { "to", "cc", "title", "content", "signature" };
    enum { NUM_TAGS = sizeof(tags) / sizeof(tags[0]) };

    printf("\nCompare variants on strtok()\n");
    {
        int i = NUM_TAGS - 1;
        printf("strtok():\n");
        parsePostData1(tags[i], data, strtok);
        printf("strtok_single():\n");
        parsePostData1(tags[i], data, strtok_single);
        printf("strtok_fixed():\n");
        parsePostData1(tags[i], data, strtok_fixed);
    }

    printf("\nCompare variants on strtok()\n");
    for (int i = 0; i < NUM_TAGS; i++)
    {
        char *value1 = parsePostData2(tags[i], data, strtok);
        printf("strtok: [%s] = [%s]\n", tags[i], value1);
        char *value2 = parsePostData2(tags[i], data, strtok_single);
        printf("single: [%s] = [%s]\n", tags[i], value2);
        char *value3 = parsePostData2(tags[i], data, strtok_fixed);
        printf("fixed:  [%s] = [%s]\n", tags[i], value3);
    }

    return 0;
}

Salida de ejemplo de emt

Compare variants on strtok()
strtok():
  [to]
  [myself@gmail.com]
  [cc]
  [youself@gmail.com]
  I need a mix of strtok and strtok_single
  [content]
  [how are you?]
  [signature]
matches signature
  [best regards.]
strtok_single():
  [to]
  [myself@gmail.com]
  [cc]
  [youself@gmail.com]
  I need a mix of strtok and strtok_single
  []
  [content]
  [how are you?]
  [signature]
matches signature
strtok_fixed():
  [to]
  [myself@gmail.com]
  [cc]
  [youself@gmail.com]
  I need a mix of strtok and strtok_single
  []
  [content]
  [how are you?]
  [signature]
matches signature
  [best regards.]

Y:

Compare variants on strtok()
✓ strtok: [to] = [myself@gmail.com]
✓ single: [to] = [myself@gmail.com]
✓ fixed:  [to] = [myself@gmail.com]
✓ strtok: [cc] = [youself@gmail.com]
✓ single: [cc] = [youself@gmail.com]
✓ fixed:  [cc] = [youself@gmail.com]
✕ strtok: I need a mix of strtok and strtok_single = [content=how are you?]
✓ single: I need a mix of strtok and strtok_single = []
✓ fixed:  I need a mix of strtok and strtok_single = []
✓ strtok: [content] = [how are you?]
✓ single: [content] = [how are you?]
✓ fixed:  [content] = [how are you?]
✓ strtok: [signature] = [best regards.]
✕ single: [signature] = [(null)]
✓ fixed:  [signature] = [best regards.]

Las marcas correctas (✓ = U+2713) e incorrectas (✕ = U+2715) se agregaron manualmente al publicar la respuesta.

Observe cómo solo las líneas etiquetadas como ‘fixed’ contienen exactamente lo que se desea cada vez.

No nos ha dicho exactamente lo que quiere decir con “esto funciona bien”, aunque parece suficiente decir que desea analizar un application/x-www-form-urlencoded cuerda. ¿Por qué no lo dijiste en primer lugar?

Considere que el primer campo, keypuede ser terminado por el primero de cualquiera '=' o '&'. Sería apropiado buscar un token que termine en cualquiera de esos caracteres, para extraer key.

El segundo campo, valuesin embargo, no es terminado por un '=' carácter, por lo que es inapropiado buscar ese carácter para extraer value. Querrás buscar '&' solamente.

Por supuesto. Tú pudo utilizar strtok para analizar esto, sin embargo, estoy seguro de que hay muchas más herramientas adecuadas. strcspnpor ejemplo, no realizará ningún cambio en datalo que significa que no necesitará hacer una copia de data como tu eres…

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

int main(void) {
    char data[]="to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards.";

    char *key = data;
    do {
        int key_length = strcspn(key, "&=");

        char *value = key + key_length + (key[key_length] == '=');
        int value_length = strcspn(value, "&");

        printf("Key:   %.*s\n"
               "Value: %.*s\n\n",
               key_length,   key,
               value_length, value);

        key = value + value_length + (value[value_length] == '&');
    } while (*key);
    return 0;
}

  • por ‘funciona bien’, quise decir que hace el trabajo de encontrar el valor de la clave dada. Lo siento, no se me pasó por la cabeza que agregar “cadena de aplicación/x-www-form-urlencoded” era importante. Muchísimas gracias por su respuesta

    – aVC

    19 de mayo de 2015 a las 4:37

  • A mi modo de ver, si un fragmento de código falla ocasionalmente, ese fragmento de código no funciona

    – autista

    19 mayo 2015 a las 10:07

  • Ok lo tengo. Para mí, ocasionalmente suena más como impredecible, lo cual es diferente en mi caso, ya que sé cuándo falla.

    – aVC

    19 mayo 2015 a las 18:00

¿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