[C] Problemino con regex

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

[C] Problemino con regex

Messaggio da Dani »

Non riesco a recuperare piu' di un'occorrenza in un'espressione...
Esempio:

Codice: Seleziona tutto

#include <stdio.h>
#include <string.h>
#include <regex.h>
#include <assert.h>
#define MAX_MATCH 50
int main (void)
{
char str[] = "AAAAAAciao1ZZZZZZ\n"
             "AAAAAAciao5ZZZZZZ\n"
             "AAAAAAciao9ZZZZZZ\n",
buff[50];

regex_t preg;
regmatch_t matches[MAX_MATCH];
u_short i;

assert (!regcomp (&preg, "ciao[0-9]", REG_EXTENDED));
assert (!regexec (&preg, str, MAX_MATCH, matches, REG_EXTENDED));

for (i = 0; matches[i].rm_so >= 0 && i < MAX_MATCH; i++)
{
strncpy (buff, str + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so); 
printf ("Match %u: %s\n", i, buff);
}
regfree (&preg);
return 0;
}
Questo codice mi restituisce solo la prima delle tre stringhe.
Ma dove sbaglio ? #-o

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: [C] Problemino con regex

Messaggio da Blizzard »

ciao,

forse non posso esserti troppo utile perchè non conosco la libreria...
ma
regexec (&preg, str, MAX_MATCH, matches, REG_EXTENDED)
non ti controlla solo la prima stringa???

Codice: Seleziona tutto

int regexec(const  regex_t  *preg,  const  char *string, size_t nmatch,
                   regmatch_t pmatch[], int eflags);
il secondo parametro è una stringa (come puntatore a char)... di conseguenza passandogli str... non solo passi un puntatore a puntatore, ma in teoria se funziona è perche str punta alla prima locazione delle 3 stringhe.

forse sto prendendo una cantonata ma prova questo
regexec (&preg, str[0], MAX_MATCH, matches, REG_EXTENDED)
regexec (&preg, str[1], MAX_MATCH, matches, REG_EXTENDED)
insomma fai un for..

posso aver scritto parecchie ca****.... ma ad occhio e croce mi sembra una cosa simile
ciao
Gio

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Problemino con regex

Messaggio da Dani »

str è una sola stringa, espressioni come str[n] portano ad un segfault :(
regexec() vuole una sola stringa, in questa ricercherà il pattern e ne memorizzerà la posizione iniziale e finale rispettivamente nei membri rm_so ed rm_eo, della struct regmatch_t.

Avatar utente
Blizzard
Master
Master
Messaggi: 1509
Iscritto il: mar 2 gen 2007, 22:53
Nome Cognome: Giovanni Santostefano
Slackware: 12.2
Kernel: 2.6.27.7-smp
Desktop: Fluxbox
Contatta:

Re: [C] Problemino con regex

Messaggio da Blizzard »

auauauauauauau scusa ho toppato! #-o
mi sembrava la dichiarazione di un array! ... =D> =D> =D> applausi per me

mmm... ma non è che regexec si ferma al primo \n \0 ????
hai provato a togliere i \n e a vedere che succede??

ciao
Gio

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Problemino con regex

Messaggio da Dani »

Togliendo i vari '\n' non cambia nulla #-o

Avatar utente
puzuma
Linux 2.x
Linux 2.x
Messaggi: 482
Iscritto il: mar 4 lug 2006, 17:14
Nome Cognome: Stefano Salvador
Slackware: current
Kernel: 2.6.32.2
Desktop: KDE 4.4.0
Località: Udine
Contatta:

Re: [C] Problemino con regex

Messaggio da puzuma »

hai interpretato male il signicato del terzo parametro di regexec, indica il numero di sottoespressioni da valutare, non i risultati, de vi usare qualcosa del tipo:

Codice: Seleziona tutto

error = regexec (&preg, str, 1, matches, 0) ;
while (error = = 0) { 
error = regexec (&preg, matches.rm_ep, 1, &matches, REG_NOTBOL) ;
}
The quiet ones are the ones who change the world. The loud ones only take the credit.

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Re: [C] Problemino con regex

Messaggio da nuitari »

Andiamo con ordine :)

Innanzitutto, ci sono un po' di erroretti. Il primo e più visibile è:

Codice: Seleziona tutto

assert (!regexec (&preg, str, MAX_MATCH, matches, REG_EXTENDED));
regexec usa flags completamente diversi da regcomp, e REG_EXTENDED è un flag di regcomp.

il secondo è:

Codice: Seleziona tutto

strncpy (buff, str + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so); 
strncpy copia pezzi di stringa SENZA aggiungere il terminatore, ovviamente. Significa che ti troverai con pezzi delle stringhe più grandi mischiati a quelli delle stringhe più piccole.. non è bello =)

Al di la di questo, il punto è:

regexec non trova tutte le occorrenze presenti in una stringa, ma solo la prima. Devi fare un ciclo se vuoi trovarle tutte, aumentando l'offset del puntatore alla stringa ogni volta ed usando ad hoc il flag REG_NOTBOL.

L'array matches è un array poichè restituisce non tutte le occorrenze di un pattern in una stringa (che per inciso è terminata da NULL, non da NEWLINE), ma le occorrenze dei subpattern, se presenti. I subpattern sono le parti della regular expression fra parentesi.
Per fartelo capire, modificherò un pelo il tuo esempio (un pelo nel senso che non lo stravolgo, anche se io l'avrei programmato diversamente):

Codice: Seleziona tutto

#include <stdio.h>
#include <string.h>
#include <regex.h>
#include <assert.h>
#define MAX_MATCH 10

int main (void)
{
        char      str[] = "AAAAAAciao1ZZZZZZAAAAAAciao5ZZZZZZ"
                , buff[50];

        regex_t preg;
        regmatch_t matches[MAX_MATCH];
        u_short i;

        assert (!regcomp (&preg, "ci(ao)", REG_EXTENDED));
        assert (!regexec (&preg, str, MAX_MATCH, matches, 0));

        for (i = 0; matches[i].rm_so >= 0 && i < MAX_MATCH; i++)
        {
                memset(buff, 0, sizeof(buff));
                strncpy (buff, str + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so);
                printf ("Match %u: %s\n", i, buff);
        }
        regfree (&preg);
        return 0;
}
Output:

Codice: Seleziona tutto

samuele@nuitari-laptop:~$ gcc prova.c && ./a.out
Match 0: ciao
Match 1: ao
Se vuoi un esempio di codice con il ciclo per trovare tutte le occorrenze, dillo =)

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Problemino con regex

Messaggio da Dani »

Per quanto riguarda gli errorini bruttini considera che è un codice scritto al volo (vedi ad esempio l'asserzione, senza verificare se regexec restituisce REG_NOMATCH...) ... Anche quando uso strncpy in genere vado a scrivere su spazio allocato con calloc(), quindi inizializzato...
A parte questo sono riuscito ad ottenere cio' che volevo, ma ancora non mi è tutto perfettamente chiaro...Le pagine di manuale delle funzioni fanno un po' pena, il manualone delle libc idem, quindi mi tocca fare prove su prove uff :(
Grazie mille !

Avatar utente
nuitari
Linux 3.x
Linux 3.x
Messaggi: 777
Iscritto il: dom 14 ott 2007, 12:51
Slackware: 12.0
Località: San Colombano al Lambro
Contatta:

Re: [C] Problemino con regex

Messaggio da nuitari »

Dimmi esattamente cosa non hai capito e ti dirò chi s... no spè . Dimmi esattamente cosa non hai capito e ti farò un esempio .

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Problemino con regex

Messaggio da Dani »

Sono tre le cose poco chiare, e tutte probabilmente richiederebbero pagine e pagine di spiegazione .
In ogni caso prima di tutto mi sfugge ancora il compito del terzo parametro di regexec(), secondariamente il significato di un flag rispetto ad un altro in entrambe le funzioni, e per finire la ricerca dei token nella stringa. In quest'utlimo caso ci sono fin quando devo trovare qualche numero, o qualche lettera, ma quando devo cercare qualcosa di piu' complesso mi impallo . Ad esempio non saprei cercare nella stringa un "ciao[...]\n\n", dove i [...] rappresentino qualsiasi cosa...
Quindi non è tanto questione di esempi pratici, ma di teoria :(

Avatar utente
gallows
Staff
Staff
Messaggi: 3470
Iscritto il: lun 20 set 2004, 0:00
Slackware: 64-current
Kernel: 5.10.7
Località: ~/
Contatta:

Re: [C] Problemino con regex

Messaggio da gallows »

Le regex posix sono un po' ostiche... ma andiamo con ordine:

1) Il terzo parametro di regexec() in realtà ha un ruolo molto semplice... in pratica funziona così:

Se passi REG_NOTBOL, significa che non considera l'inizio della stringa come l'inizio di una linea... ovvero:

Codice: Seleziona tutto

char str[] = ""
        "0x000A prima riga\n"
        "0x000B seconda riga\n";
		
char pattern[] = "^0x000.";

regcomp(&preg, pattern, REG_NEWLINE);
regexec(&preg, str, 1, &match, REG_NOTBOL);
Come match avrai 0x000B, perché l'inizio della stringa non viene considerato come l'inizio della prima riga, è come se prima di 0x000A ci fossero altri caratteri.

REG_NOTEOL è speculare. Vale per la fine della stringa. (Quindi con '$' invece che '^').

2) Il manuale mi sembra spieghi bene le cflags, capite le altre sei a cavallo. Cosa non ti è chiaro?

3)

Codice: Seleziona tutto

char str[] = ""
        "0123456789\n"
        "foobarciaoquxquux\n\n"
        "blablablabla\n";
char pattern[] = "ciao.*\n\n";

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Problemino con regex

Messaggio da Dani »

gallows ha scritto:

Codice: Seleziona tutto

char str[] = ""
        "0123456789\n"
        "foobarciaoquxquux\n\n"
        "blablablabla\n";
char pattern[] = "ciao.*\n\n";
Perchè se alla terza riga aggiungo un altro newline, quest'ultimo sarà l'offset finale ? Non dovrebbe fermarsi al secondo newline della seconda riga e settare qui rm_eo !?

Rispondi