Newsgroup: it.comp.lang.c
Titolo: estrazione di sottostringhe da una stringa

ho il seguente problema:
da un file ascii costituito da molte righe di lunghezza di circa 600
caratteri ci sono delle informazioni separate dai caratteri ";" Ovvero
sono più campi di lunghezza diversa e separati dai ";".
Per esempio:
campo1;campo2;campo3;...;
Devo estrarre, per ogni riga, i singoli campi e metterli in un vettore
per poi gestirli a parte.
Ho ripetutamente provato con le varie funzioni di manipolazione sulle
stringhe e in particolare con "STRCSPN" ma dopo che ho trovato il primo
delimitatore ";" il compilatore genera un errore.
Penso che sia dovuto al fatto che faccio confusione con i puntatori
"*ptr".
Non sono molto bravo afd impiegarli.
Qualcuno può indicarmi un metodo alternativo oppure un loro esatto
impiego in questo problema?
Grazie
LI
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

impiego in questo problema?
Ti viene molto bene con una tokenizer. Quella della libreria standard
funziona, ma ha alcuni problemi.
L'idea e' che chiami la funzione passandogli come primo parametro la
stringa da analizzare e come secondo la stringa dei delimitatori.
Qui cambia il modo di chiamata tra la funzione che ti allego io e
quella della standard library.
La strtok() vuole alla prima chiamata la stringa da parsificare come
primo parametro, dalla seconda in poi vuole NULL (si fa' una copia
locale della stringa e lavora su quella... brutto, controintuitivo e
non funziona in caso di multiprocesso/multithread). Quella che ti
allego io modifica direttamente il primo parametro.
<CODE author="Wietse Venema">
#include <string.h>
/* mystrtok - safe tokenizer */
char   *mystrtok(char **src, const char *sep)
{
    char   *start = *src;
    char   *end;
    /*
     * Skip over leading delimiters.
     */
    start += strspn(start, sep);
    if (*start == 0) {
	*src = start;
	return (0);
    }
    /*
     * Separate off one token.
     */
    end = start + strcspn(start, sep);
    if (*end != 0)
	*end++ = 0;
    *src = end;
    return (start);
}
La chiamera' cosi':
char * res;
/* non molto bella l'assegnamento nel while, ma qui e' comodo */
while (res = mystrtok("aaa;bbb;c d ef -g", ";"))
    puts (res);
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

 in un vettore per poi gestirli a parte.
La funzione più idonea a questo tipo di operazioni è strtok. La richiami una
prima volta passando come parametri la stringa e il separatore e ti
restituisce il primo campo:
    token = strtok(stringa, ";");
per ottenere i campi successivi richiami la stessa funzione mettendo NULL al
posto di stringa, finchè non ti viene riportato NULL:
    i = 0;
    do {
        strcpy(campo[i++], token);
    } while (token = strtok(NULL, ";"));
Maurizio.

 
La strtok ha come problema principale il fatto che dopo che ha
analizzato
una stringa questa e' persa. Inoltre fa uso di un buffer static: se
chiami
una funzione che a sua volta chiama lo strtok succedono casini
inenarrabili :-)
Meglio farsene una per fatti propri come suggerito da Mox.
C:\>iao Angelo

 si avvicino` a me, e solennemente disse: 
[snip]
per estrapolare indirizzo e porta da stringhe del genere ADDRESS:PORT io uso in
genere il seguente codice:
<CODE>
short int get_host_port(char *host)
{
        char *p;
        unsigned short int port;
        if ((p=strchr(host, ':')) == NULL)
        {
                fprintf(stderr,"(%s) strchr() failed: uncorrect"
				"string format.\n",__FUNCTION__);
                fflush(stderr);
                return -1;
        }
        *p='\0';
        /* the control below is redundant and paranoic,
         * because on almost all calculators a short int is
         * a 16-bit value, so it can grow up to 65536 only;
         * but could happen that a few machines assumes a
         * short int > 16bit...
         */
        if ( (port=atoi(++p)) < 0 || port > 65536)
        {
                printf("\nPORT too high, please specify a number less"
				"or equal than 65536\n");
                return -1;
        }
        return port;
}
</CODE>
questo mi ritorna la porta e mi sostituisce a *host la stringa contenente il
solo indirizzo.
Con una (o un paio) di strdup() prima, e ficcandolo in un loop, potrebbe
risolvere il problema?
Adieu,
-- 
Lestat de Lioncourt                               |          Ciro Mattia Gonano
  JabberID: 
les...@jabber.students.cs.unibo.it
    |    Undergraduate Student in
  ICQ#: 52631406                                  |         Computer Science at
  URL: 
http://www.CS.UniBO.It/~gonano
             |       University of Bologna
          <powered by Linux Slackware 8.1-rc3 on Kernel 2.4.18-xfs>

risolvere il problema?
Si e no: funziona (nel problema specifico), ma non aggiungi potenza al
metodo suggerito.
Analizziamo 2 aspetti: il processo di pattern matching e
l'elaborazione della stringa in input.
Per quanto riguarda il pattern matching, la complessita' potrebbe
essere leggermente inferiore usando una strstr (o meglio ancora una
strchr), perche' devi controllare un solo char, cosa che e' mediamente
meno costosa che non una chiamata a strspn (quella che usi nella
tokenizer).
Attenzione pero': nel caso funziona egregiamente, ma smette di
funzionare se hai piu' delimitatori possibili, come soluzione la
tokenizer e' piu' flessibile.
Per l'elaborazione alla fine ti conviene fare quello che fa' la
tokenizer, indipendentemente da che metodo hai usato per trovare il
delimitatore tra le 2 stringhe: ovvero sostituirlo con un '\0' per
poter usare comodamente le funzioni che operano sulle stringhe...
questo non tanto nel caso della copia, che puo' risultare piu'
conveniente con una memmove, ma per tutte le altre funzioni che si
aspettano una stringa 0-terminata.
Non ho un man a portata ora, ma credo che anche la strdup() che usi
(fornita con la libreria gnu se non sbaglio) non funzioni bene se non
metti il terminatore di stringa :)


 
uhmmy... "man strdup" dice che e` conforme allo SVID 3 e BSD 4.3... in compenso
strndup(), strdupa() e strndupa() sono estensioni GNU.
Cmq non penso sia un problema, o almeno, nel man non ne fa menzione... strdup()
si limita ad allocare (con malloc() ) _strlen_ bytes di memoria, copiarci dentro
la stringa presa in argomento, e ritornare il puntatore alla memoria allocata.
Da come l'ho capita io, sarebbe una sequenza (con dest gia dichiarato):
<CODE>
{dest=malloc(strlen(const char *s));strcpy(dest,s)}
</CODE>
..ma potrei sbagliarmi.
Adieu,
-- 
Lestat de Lioncourt                               |          Ciro Mattia Gonano
  JabberID: 
les...@jabber.students.cs.unibo.it
    |    Undergraduate Student in
  ICQ#: 52631406                                  |         Computer Science at
  URL: 
http://www.CS.UniBO.It/~gonano
             |       University of Bologna
         <powered by Linux Slackware 8.1-beta2 on Kernel 2.4.18-xfs>