Tokenisierung von Strings in C

Lesezeit: 6 Minuten

Benutzer-Avatar
Kombi

Ich habe versucht, eine Zeichenfolge mit SPACE als Trennzeichen zu tokenisieren, aber es funktioniert nicht. Hat jemand einen Vorschlag, warum es nicht funktioniert?

Bearbeiten: Tokenisierung mit:

strtok(string, " ");

Der Code sieht wie folgt aus

pch = strtok (str," ");
while (pch != NULL)
{
  printf ("%s\n",pch);
  pch = strtok (NULL, " ");
}

  • Verwenden Sie strtok oder etwas, das Sie selbst entwickelt haben? cplusplus.com/reference/clibrary/cstring/strtok.html Wenn Sie strtok verwenden, versuchen Sie es mit einer konstanten Zeichenfolge?

    – Eduard Kmett

    5. November 2008 um 19:48 Uhr

  • Ihr Beispiel wird das erste Token erhalten, schauen Sie sich entweder die Antworten von gbjbaanb oder meine Antworten für die richtige Verwendung an.

    – Evan Teran

    5. November 2008 um 20:02 Uhr

  • OK. Jetzt kommen wir irgendwo hin. Welches Verhalten erwarten Sie, das Sie nicht bekommen?

    – dmckee — Ex-Moderator-Kätzchen

    5. November 2008 um 20:08 Uhr

  • Übrigens, Kombo. Viele Menschen, die an Helpdesks arbeiten oder lehren, sehen den Ausdruck „es funktioniert nicht“ als Kennzeichnung eines Benutzers, der das bereitgestellte Handbuch nicht gelesen hat oder nicht weiß, was er eigentlich will, oder zutiefst verwirrt ist. Die Form, die Sie wollen, ist “Ich mache X, und ich habe Y erwartet, aber ich habe Z bekommen. Was ist falsch?”

    – dmckee — Ex-Moderator-Kätzchen

    5. November 2008 um 20:17 Uhr

  • @dmckee: guter Punkt. Kanonische X-Referenz: catb.org/~esr/faqs/smart-questions.html

    – Jonathan Leffler

    5. November 2008 um 22:46 Uhr

Benutzer-Avatar
gbjbaanb

Mach es so:

char s[256];
strcpy(s, "one two three");
char* token = strtok(s, " ");
while (token) {
    printf("token: %s\n", token);
    token = strtok(NULL, " ");
}

Notiz: strtok ändert die Zeichenfolge in ihre Tokenisierung, sodass sie nicht a sein kann const char*.

Benutzer-Avatar
Evan Teran

Hier ist ein Beispiel für strtok Verwendung, denken Sie daran strtok ist destruktiv für seine Eingabezeichenfolge (und kann daher nicht je auf eine String-Konstante verwendet werden

char *p = strtok(str, " ");
while(p != NULL) {
    printf("%s\n", p);
    p = strtok(NULL, " ");
}

Grundsätzlich ist zu beachten, dass das Bestehen von a NULL als erster Parameter zu strtok weist es an, das nächste Token aus der Zeichenfolge zu holen, die es zuvor tokenisiert hat.

  • strtok hat eine interne Zustandsvariable, die die Zeichenfolge verfolgt, die in Tokens umgewandelt wird. Wenn du passierst NULL dazu, strtok wird diese Zustandsvariable weiterhin verwenden. Wenn Sie einen Wert ungleich Null übergeben, wird die Zustandsvariable zurückgesetzt. Also mit anderen Worten: vorbei NULL bedeutet “mit der Tokenisierung derselben Zeichenfolge fortfahren”.

    – Evan Teran

    27. Februar 2012 um 15:51 Uhr

  • Sie haben Recht, deshalb bieten sich viele Implementierungen an strtok_r was zumindest eine Möglichkeit bietet, es Thread-sicher zu verwenden.

    – Evan Teran

    28. Februar 2012 um 5:53 Uhr

  • @Gnuey, p zeigt auf Zeichen in die Zeichenfolge, die tokenisiert wird. Zusätzlich, strtok ersetzt das gefundene Trennzeichen durch a '\0' Charakter damit p wird effektiv gültig sein NUL abgeschlossene Zeichenfolge. Also, wenn Sie es weiterführen würden char[] s = "hello world"; Der erste Aufruf würde einen Zeiger auf die zurückgeben h Zeichen und der Puffer würde dann enthalten "hello\0world".

    – Evan Teran

    21. Oktober 2014 um 17:56 Uhr

Benutzer-Avatar
Kieveli

strtok kann sehr gefährlich sein. Es ist nicht threadsicher. Seine beabsichtigte Verwendung besteht darin, immer wieder in einer Schleife aufgerufen zu werden, wobei die Ausgabe des vorherigen Aufrufs übergeben wird. Die strtok-Funktion hat eine interne Variable, die den Status des strtok-Aufrufs speichert. Dieser Zustand ist nicht für jeden Thread einzigartig – er ist global. Wenn ein anderer Code strtok in einem anderen Thread verwendet, treten Probleme auf. Nicht die Art von Problemen, die Sie aufspüren möchten!

Ich würde empfehlen, nach einer Regex-Implementierung zu suchen oder sscanf zu verwenden, um die Zeichenfolge auseinanderzuziehen.

Versuche dies:

char strprint[256];
char text[256];
strcpy(text, "My string to test");
while ( sscanf( text, "%s %s", strprint, text) > 0 ) {
   printf("token: %s\n", strprint);
}

Hinweis: Die Zeichenfolge „text“ wird zerstört, wenn sie getrennt wird. Dies ist möglicherweise nicht das bevorzugte Verhalten =)

  • Wenn Sie sich moderne strtok-Implementierungen ansehen, neigen sie tatsächlich dazu, Thread-lokalen Speicher zu verwenden (MSVC hat dies sicherlich seit Jahren getan), sodass sie Thread-sicher sind. Es ist immer noch eine archaische Funktion, die ich jedoch vermeiden würde …

    – Will Dekan

    5. November 2008 um 20:37 Uhr

  • strtok_r ist eine Thread-sichere Version von strtok pubs.opengroup.org/onlinepubs/009695399/functions/strtok.html

    – Massimo Fazzolari

    5. September 2012 um 18:47 Uhr

  • Ich stimme dem ersten Absatz zu, aber der Satz danach ist schrecklich. scanf ist schwer richtig zu verwenden, wie in Ihrem Beispiel gezeigt; Sie haben vergessen, eine Größe zu übergeben (%255s).

    – SS Anne

    15. Februar 2020 um 18:01 Uhr

  • strtok() ist jedoch in Ordnung für Legacy-Systeme ohne Threads. Archaischer Code für Retro-Systeme.

    – rje

    2. September 2021 um 20:53 Uhr


Benutzer-Avatar
Ferruccio

Sie können den Code vereinfachen, indem Sie eine zusätzliche Variable einführen.

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

int main()
{
    char str[100], *s = str, *t = NULL;

    strcpy(str, "a space delimited string");
    while ((t = strtok(s, " ")) != NULL) {
        s = NULL;
        printf(":%s:\n", t);
    }
    return 0;
}

Ich habe einige Zeichenfolgenfunktionen erstellt, um Werte aufzuteilen, indem ich weniger Zeiger als möglich verwende, da dieser Code auf PIC18F-Prozessoren ausgeführt werden soll. Diese Prozessoren können mit Zeigern nicht wirklich gut umgehen, wenn Sie wenig freien RAM zur Verfügung haben:

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

char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A";

int findchar(char *string, int Start, char C) {
    while((string[Start] != 0)) { Start++; if(string[Start] == C) return Start; }
    return -1;
}

int findcharn(char *string, int Times, char C) {
   int i = 0, pos = 0, fnd = 0;

    while(i < Times) {
       fnd = findchar(string, pos, C);
        if(fnd < 0) return -1;
        if(fnd > 0) pos = fnd;
       i++;
   }
   return fnd;
}

void mid(char *in, char *out, int start, int end) {
    int i = 0;
    int size = end - start;

    for(i = 0; i < size; i++){
        out[i] = in[start + i + 1];
    }
    out[size] = 0;
}

void getvalue(char *out, int index) {
    mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1));
}

void main() {
   char n_pwd[7];
   char n_d1[7];

   getvalue(n_d1, 1);

   printf("Value: %s\n", n_d1);
} 

Benutzer-Avatar
xtofl

Beim Lesen der strtok-Dokumentation sehe ich, dass Sie nach dem ersten “Initialisierungs”-Aufruf einen NULL-Zeiger übergeben müssen. Vielleicht hast du das nicht getan. Natürlich nur eine Vermutung.

Benutzer-Avatar
fnisi

Hier ist ein anderer strtok() Implementierung, die in der Lage ist, aufeinanderfolgende Trennzeichen zu erkennen (Standardbibliotheks strtok() hat das nicht)

Die Funktion ist ein Teil der BSD-lizenzierten String-Bibliothek namens zString. Sie sind mehr als willkommen, einen Beitrag zu leisten 🙂

https://github.com/fnoyanisi/zString

char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}

Wie in früheren Beiträgen erwähnt, da strtok()oder die, die ich oben implementiert habe, beruht auf a static *char -Variable, um die Position des letzten Trennzeichens zwischen aufeinanderfolgenden Aufrufen beizubehalten, sollten Sie beim Umgang mit Multithread-Anwendungen besonders vorsichtig sein.

1354720cookie-checkTokenisierung von Strings in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy