Saltar al contenido

Expresiones regulares de C: extracción de coincidencias reales

Si te encuentras con algún detalle que no entiendes puedes dejarnos un comentario y haremos todo lo necesario de ayudarte lo mas rápido que podamos.

Solución:

Hay bastantes paquetes de expresiones regulares, pero el suyo parece coincidir con el de POSIX: regcomp() etc.

Las dos estructuras que define en son:

  • regex_t conteniendo al menos size_t re_nsub, el número de subexpresiones entre paréntesis.

  • regmatch_t conteniendo al menos regoff_t rm_so, el byte offset desde el inicio de string al inicio de la subcadena, y regoff_t rm_eo, el byte offset desde el inicio de string del primer carácter después del final de la subcadena.

Tenga en cuenta que las 'compensaciones' no son punteros sino índices en el carácter array.

La función de ejecución es:

  • int regexec(const regex_t *restrict preg, const char *restrict string,
    size_t nmatch, regmatch_t pmatch[restrict], int eflags);

Su código de impresión debe ser:

for (int i = 0; i <= r.re_nsub; i++)

    int start = m[i].rm_so;
    int finish = m[i].rm_eo;
//  strcpy(matches[ind], ("%.*sn", (finish - start), p + start));  // Based on question
    sprintf(matches[ind], "%.*sn", (finish - start), p + start);   // More plausible code
    printf("Storing:  %.*sn", (finish - start), matches[ind]);     // Print once
    ind++;
    printf("%.*sn", (finish - start), p + start);                  // Why print twice?

Tenga en cuenta que el código debe actualizarse para garantizar que el string copiar (a través de sprintf()) no desborda el objetivo string - tal vez usando snprintf() en vez de sprintf(). También es una buena idea marcar el inicio y el final de un string en la imprenta. Por ejemplo:

    printf("<<%.*s>>n", (finish - start), p + start);

Esto hace que sea mucho más fácil ver espacios, etc.

[In future, please attempt to provide an MCVE (Minimal, Complete, Verifiable Example) or SSCCE (Short, Self-Contained, Correct Example) so that people can help more easily.]

Este es un SSCCE que creé, probablemente en respuesta a otra pregunta SO en 2010. Es uno de varios programas que mantengo y que llamo 'viñetas'; pequeños programas que muestran la esencia de alguna característica (como las expresiones regulares POSIX, en este caso). Los encuentro útiles para mejorar la memoria.

#include 
#include 
#include 
#include 
#include 

#define tofind    "^DAEMONS=\(([^)]*)\)[ t]*$"

int main(int argc, char **argv)

    FILE *fp;
    char line[1024];
    int retval = 0;
    regex_t re;
    regmatch_t rm[2];
    //this file has this line "DAEMONS=(sysklogd network sshd !netfs !crond)"
    const char *filename = "/etc/rc.conf";

    if (argc > 1)
        filename = argv[1];

    if (regcomp(&re, tofind, REG_EXTENDED) != 0)
    
        fprintf(stderr, "Failed to compile regex '%s'n", tofind);
        return EXIT_FAILURE;
    
    printf("Regex: %sn", tofind);
    printf("Number of captured expressions: %zun", re.re_nsub);

    fp = fopen(filename, "r");
    if (fp == 0)
    
        fprintf(stderr, "Failed to open file %s (%d: %s)n", filename, errno, strerror(errno));
        return EXIT_FAILURE;
    

    while ((fgets(line, 1024, fp)) != NULL)
    
        line[strcspn(line, "n")] = '';
        if ((retval = regexec(&re, line, 2, rm, 0)) == 0)
        
            printf("<<%s>>n", line);
            // Complete match
            printf("Line: <<%.*s>>n", (int)(rm[0].rm_eo - rm[0].rm_so), line + rm[0].rm_so);
            // Match captured in (...) - the ( and ) match literal parenthesis
            printf("Text: <<%.*s>>n", (int)(rm[1].rm_eo - rm[1].rm_so), line + rm[1].rm_so);
            char *src = line + rm[1].rm_so;
            char *end = line + rm[1].rm_eo;
            while (src < end)
            
                size_t len = strcspn(src, " ");
                if (src + len > end)
                    len = end - src;
                printf("Name: <<%.*s>>n", (int)len, src);
                src += len;
                src += strspn(src, " ");
            
        
     
    return EXIT_SUCCESS;

Esto fue diseñado para encontrar una línea particular comenzando DAEMONS= en un archivo /etc/rc.conf (pero puede especificar un nombre de archivo alternativo en la línea de comando). Puede adaptarlo a sus propósitos con bastante facilidad.

Te invitamos a defender nuestro análisis dejando un comentario y dejando una valoración te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada.