2012-09-17 20 views
9

Diciamo che sto usando strtok() come questo ..C - Determinare quali delimitatore utilizzato - strtok()

char *token = strtok(input, ";-/"); 

C'è un modo per capire quali simbolici in realtà viene utilizzato? Per esempio, se gli ingressi era qualcosa di simile:

Hello there; How are you?/I'm good - End

Posso capire quale delimitatore è stato utilizzato per ogni gettone? Devo essere in grado di generare un messaggio specifico, a seconda del delimitatore che ha seguito il token.

+1

Per info, quando l'uomo strtok: Questa interfaccia è obsoleto da strsep (3). – Geoffroy

+0

No, ma se si fa una domanda per chiedere una versione che lo fa, qualcuno potrebbe scriverne uno. char * strtok_new (char * string, const char * delimiters, char * corrisponde); – Scooter

+0

Si noti che 'strsep' non è in C o Posix (anche se' strtok_r' è in Posix e 'strtok_s' è in C11), ma è in LSB e BSD. Quindi 'strtok' è obsoleto da' strsep' su alcuni sistemi e non su altri. La cosa sulle pagine man è che si applicano solo al sistema in cui ti trovi quando usi 'man'. –

risposta

8

Importante: strtok non è ri-entrante, si dovrebbe usare strtok_r invece di esso.

Puoi farlo salvando una copia della stringa originale, e guardando in offset del token corrente in quella copia:

char str[] = "Hello there; How are you?/I'm good - End"; 
char *copy = strdup(str); 
char *delim = ";-/"; 
char *res = strtok(str, delim); 
while (res) { 
    printf("%c\n", copy[res-str+strlen(res)]); 
    res = strtok(NULL, delim); 
} 
free(copy); 

Questo stampa

; 
/
- 

Demo #1

MODIFICA:Gestione di delimitatori multipli

Se è necessario gestire più delimitatori, determinare la lunghezza della sequenza corrente di delimitatori diventa leggermente più difficile: ora è necessario trovare il token successivo prima di decidere quanto è lunga la sequenza dei delimitatori.La matematica non è complicato, a patto che vi ricordate che NULL richiede un trattamento speciale:

char str[] = "(20*(5+(7*2)))+((2+8)*(3+6*9))"; 
char *copy = strdup(str); 
char *delim = "*+()"; 
char *res = strtok(str, delim); 
while (res) { 
    int from = res-str+strlen(res); 
    res = strtok(NULL, delim); 
    int to = res != NULL ? res-str : strlen(copy); 
    printf("%.*s\n", to-from, copy+from); 
} 
free(copy); 

Demo #2

+0

Grazie, questo è il tipo di comportamento che speravo di ottenere. –

+0

@dasblinkenlight, questo non funzionerà se si dispone di separatore multiplo in successione. per esempio considera la tokenizzazione dell'espressione aritmetica 20 * 5 + (7 * 2) dove definisci il tuo delim come "+ -/*()" e sei interessato alla tokenizzazione dell'operatore e degli operandi. + (non verrà tokenizzato correttamente. – David

+1

@David Hai ragione, il codice presuppone che ci sia sempre un delimitatore, tuttavia c'è una soluzione semplice per questo: tutto ciò che devi fare è ottenere il prossimo token per decidere quanto tempo è l'attuale sequenza di delimitatori (vedi la modifica e la demo) – dasblinkenlight

3

Non è possibile. strtok sovrascrive il carattere separatore successivo con un carattere nul (per terminare il token che sta tornando questa volta) e non memorizza il valore precedente che sovrascrive. La prima volta che si chiama strtok sulla stringa di esempio, lo ; è sparito per sempre.

Si potrebbe fare qualcosa se si mantiene una copia non modificata della stringa che si sta modificando con strtok - dato l'indice del terminatore nul per il token corrente (relativo all'inizio della stringa), si può guardare il stesso indice nella copia e vedere cosa c'era.

Questo potrebbe essere peggio di scrivere semplicemente il proprio codice per separare la stringa, ovviamente. È possibile utilizzare strpbrk o strcspn, se è possibile vivere con il token risultante che non viene annullato automaticamente.

1

man 3 strtok

Lo strtok() e strtok_r (funzioni) restituisce un puntatore alla all'inizio di ogni successivo gettone nella stringa, dopo aver sostituito il token stessa con un carattere NUL. Quando non rimangono più token , viene restituito un puntatore nullo.

Ma con un po 'di aritmetica dei puntatori si può fare qualcosa di simile:

char* string = "Hello,World!"; 
char* dup = strdup(string); 

char* world = strtok(string, ","); 
char delim_used = dup[world - string]; 

free(dup);