wake-up-neo.net

Wie teilt strtok () die Zeichenfolge in C in Token auf?

Erklären Sie mir bitte die Funktionsweise von strtok() function. Das Handbuch sagt, es zerlegt die Zeichenfolge in Zeichenketten. Ich kann aus dem Handbuch nicht verstehen, was es tatsächlich tut.

Ich habe Uhren zu str und *pch hinzugefügt, um die Funktion zu überprüfen. Als die erste while-Schleife auftrat, war der Inhalt von str nur "this". Wie wurde die unten gezeigte Ausgabe auf dem Bildschirm gedruckt?

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

Ausgabe:

 Aufteilungszeichenfolge "- Dies ist eine Beispielzeichenfolge." in Token: 
 Diese 
 ein 
 sample 
 string 
87
Fahad Uddin

strtok() teilt die Zeichenfolge in Token auf. Das heißt, von einem der Trennzeichen bis zum nächsten würde Ihr einziger Token sein. In Ihrem Fall ist das Startzeichen "-" und endet mit dem nächsten Leerzeichen "". Das nächste Token beginnt dann mit "" und endet mit ",". Hier erhalten Sie "This" als Ausgabe. In ähnlicher Weise wird der Rest der Zeichenfolge in Zeichen von Leerzeichen zu Leerzeichen aufgeteilt und schließlich das letzte Zeichen auf "."

35
Sachin Shanbhag

die Funktion strtok Runtime funktioniert so

beim ersten Aufruf von strtok geben Sie eine Zeichenfolge an, die Sie tokenisieren möchten

char s[] = "this is a string";

in der obigen Zeichenkette scheint Leerzeichen ein gutes Trennzeichen zwischen Wörtern zu sein.

char* p = strtok(s, " ");

was jetzt passiert ist, dass 's' gesucht wird, bis das Leerzeichen gefunden ist, das erste Token zurückgegeben wird ('this') und p auf dieses Token (Zeichenfolge) zeigt.

um das nächste Token zu erhalten und mit derselben Zeichenfolge fortzufahren, wird NULL als erstes Argument übergeben Argument, da strtok einen statischen Zeiger auf die zuvor übergebene Zeichenfolge enthält:

p = strtok(NULL," ");

p zeigt jetzt auf 'ist'

und so weiter, bis keine Leerzeichen mehr gefunden werden können. Dann wird die letzte Zeichenfolge als letzte Zeichenfolge 'Zeichenfolge' zurückgegeben.

bequemer könnte man es so schreiben, um alle Token auszudrucken:

for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
  puts(p);
}

BEARBEITEN:

Wenn Sie die zurückgegebenen Werte von strtok speichern möchten, müssen Sie das Token in einen anderen Puffer kopieren, z. strdup(p);, da der ursprüngliche String (auf den der statische Zeiger in strtok zeigt) zwischen den Iterationen geändert wird, um das Token zurückzugeben.

176
Anders

strtok verwaltet eine statische interne Referenz, die auf das nächste verfügbare Token in der Zeichenfolge verweist. Wenn Sie einen NULL-Zeiger übergeben, wird dieser interne Verweis verwendet. 

Dies ist der Grund, warum strtok kein Wiedereinsteiger ist. Sobald Sie einen neuen Zeiger übergeben, wird die alte interne Referenz verfälscht. 

19
John Bode

strtok ändert den Parameter selbst nicht (str). Es speichert diesen Zeiger (in einer lokalen statischen Variablen). Es kann dann ändern, was der Parameter in nachfolgenden Aufrufen auf zeigt, ohne dass der Parameter zurückgegeben wird. (Und es kann den Zeiger vorrücken, den es beibehalten hat, aber es muss seine Operationen ausführen.)

Von der POSIX strtok Seite:

Diese Funktion verwendet statischen Speicher, um die aktuelle Zeichenfolgenposition zwischen Aufrufen zu verfolgen.

Es gibt eine Thread-sichere Variante (strtok_r), die diese Art von Magie nicht durchführt.

10
Mat

Beim ersten Aufruf geben Sie die Zeichenfolge an, die in strtok tokenisiert werden soll. Und um die folgenden Token zu erhalten, geben Sie einfach NULL an diese Funktion, solange sie einen nicht NULL-Zeiger zurückgibt.

Die Funktion strtok zeichnet die Zeichenfolge auf, die Sie beim Aufruf zuerst angegeben haben. (Was für Multithread-Anwendungen wirklich gefährlich ist)

7
tibur

strtok wird eine Zeichenkette mit einem Token versehen, d. h. in eine Reihe von Teilzeichenfolgen konvertieren.

Dies geschieht durch Suchen nach Trennzeichen, die diese Token (oder Teilzeichenfolgen) voneinander trennen. Und Sie geben die Trennzeichen an. In Ihrem Fall möchten Sie '' oder ',' oder '.' oder '-' als Trennzeichen.

Das Programmiermodell zum Extrahieren dieser Token besteht darin, dass Sie Ihre Hauptzeichenfolge und die Menge der Trennzeichen übergeben. Dann rufen Sie es wiederholt an und jedes Mal gibt strtok das nächste gefundene Token zurück. Bis zum Ende der Hauptzeichenfolge wird eine Null zurückgegeben. Eine andere Regel ist, dass Sie die Zeichenfolge nur beim ersten Mal und NULL für die nachfolgenden Zeiten übergeben. Dies ist eine Möglichkeit, strtok mitzuteilen, ob Sie eine neue Sitzung mit Tokenisierung mit einer neuen Zeichenfolge beginnen oder Token aus einer vorherigen Tokenisierungssitzung abrufen. Beachten Sie, dass strtok seinen Status für die tokenisierende Sitzung speichert. Aus diesem Grund ist es weder wiedereintrittsfähig noch fadensicher (stattdessen sollten Sie strtok_r verwenden). Eine andere Sache zu wissen ist, dass es die ursprüngliche Zeichenfolge tatsächlich ändert. Es schreibt '\ 0' für die gefundenen Trennzeichen.

Eine Möglichkeit, strtok kurz und bündig aufzurufen, ist wie folgt:

char str[] = "this, is the string - I want to parse";
char delim[] = " ,-";
char* token;

for (token = strtok(str, delim); token; token = strtok(NULL, delim))
{
    printf("token=%s\n", token);
}

Ergebnis:

this
is
the
string
I
want
to
parse
5
Ziffusion

strtok ändert seine Eingabezeichenfolge. Es fügt Nullzeichen ('\ 0') ein, so dass die Bits des ursprünglichen Strings als Token zurückgegeben werden. In der Tat weist strtok keinen Speicher zu. Sie können es besser verstehen, wenn Sie die Zeichenfolge als Folge von Boxen zeichnen. 

4
xpmatteo

Um zu verstehen, wie strtok() funktioniert, muss man zunächst wissen, was eine static variable ist. Dieser Link erklärt es ganz gut ....

Der Schlüssel für die Operation von strtok() ist die Beibehaltung des Speicherorts des letzten Separators zwischen aufeinanderfolgenden Aufrufen (aus diesem Grund analysiert strtok() weiterhin die sehr ursprüngliche Zeichenfolge, die an ihn übergeben wird, wenn er in aufeinanderfolgenden Aufrufen mit einem null pointer aufgerufen wird).

Schauen Sie sich meine eigene strtok()-Implementierung mit dem Namen zStrtok() an, deren Funktionalität sich geringfügig von der von strtok() bereitgestellten unterscheidet.

char *zStrtok(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;
}

Und hier ist eine Beispielanwendung

  Example Usage
      char str[] = "A,B,,,C";
      printf("1 %s\n",zStrtok(s,","));
      printf("2 %s\n",zStrtok(NULL,","));
      printf("3 %s\n",zStrtok(NULL,","));
      printf("4 %s\n",zStrtok(NULL,","));
      printf("5 %s\n",zStrtok(NULL,","));
      printf("6 %s\n",zStrtok(NULL,","));

  Example Output
      1 A
      2 B
      3 ,
      4 ,
      5 C
      6 (null)

Der Code stammt von einer Stringbearbeitungsbibliothek, die ich auf Github pflege, genannt zString. Schauen Sie sich den Code an oder tragen Sie auch dazu bei:) https://github.com/fnoyanisi/zString

3
Fehmi Noyan ISI

strtok ersetzt die Zeichen im zweiten Argument durch NULL und ein NULL-Zeichen ist auch das Ende einer Zeichenfolge.

http://www.cplusplus.com/reference/clibrary/cstring/strtok/

1
Patrick

Hier ist meine Implementierung, die Hash-Tabelle für das Trennzeichen verwendet, dh es ist O(n) anstelle von O (n ^ 2) (hier ist ein Link zum Code) :

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

#define DICT_LEN 256

int *create_delim_dict(char *delim)
{
    int *d = (int*)malloc(sizeof(int)*DICT_LEN);
    memset((void*)d, 0, sizeof(int)*DICT_LEN);

    int i;
    for(i=0; i< strlen(delim); i++) {
        d[delim[i]] = 1;
    }
    return d;
}



char *my_strtok(char *str, char *delim)
{

    static char *last, *to_free;
    int *deli_dict = create_delim_dict(delim);

    if(!deli_dict) {
        /*this check if we allocate and fail the second time with entering this function */
        if(to_free) {
            free(to_free);
        }
        return NULL;
    }

    if(str) {
        last = (char*)malloc(strlen(str)+1);
        if(!last) {
            free(deli_dict);
            return NULL;
        }
        to_free = last;
        strcpy(last, str);
    }

    while(deli_dict[*last] && *last != '\0') {
        last++;
    }
    str = last;
    if(*last == '\0') {
        free(deli_dict);
        free(to_free);
        deli_dict = NULL;
        to_free = NULL;
        return NULL;
    }
    while (*last != '\0' && !deli_dict[*last]) {
        last++;
    }

    *last = '\0';
    last++;

    free(deli_dict);
    return str;
}

int main()
{
    char * str = "- This, a sample string.";
    char *del = " ,.-";
    char *s = my_strtok(str, del);
    while(s) {
        printf("%s\n", s);
        s = my_strtok(NULL, del);
    }
    return 0;
}
1
Kohn1001

strtok () speichert den Zeiger in der statischen Variablen, wo Sie das letzte Mal aufgehört haben. Beim zweiten Aufruf, wenn wir die Null übergeben, erhält strtok () den Zeiger von der statischen Variablen.

Wenn Sie denselben Stringnamen angeben, beginnt er wieder von vorne.

Darüber hinaus ist strtok () destruktiv, d. H. Es werden Änderungen an der Originalzeichenfolge vorgenommen. Stellen Sie daher sicher, dass Sie immer eine Kopie von Original haben.

Ein weiteres Problem bei der Verwendung von strtok () besteht darin, dass der Aufruf von strtok () bei der Multithread-Programmierung, da er die Adresse in statischen Variablen speichert, einen Fehler verursacht. Verwenden Sie hierfür strtok_r ().

1
Vaibhav

So habe ich strtok implementiert. Nicht so toll, aber nachdem ich 2 Stunden gearbeitet hatte, war es endlich soweit. Es unterstützt mehrere Trennzeichen.

#include "stdafx.h"
#include <iostream>
using namespace std;

char* mystrtok(char str[],char filter[]) 
{
    if(filter == NULL) {
        return str;
    }
    static char *ptr = str;
    static int flag = 0;
    if(flag == 1) {
        return NULL;
    }
    char* ptrReturn = ptr;
    for(int j = 0; ptr != '\0'; j++) {
        for(int i=0 ; filter[i] != '\0' ; i++) {
            if(ptr[j] == '\0') {
                flag = 1;
                return ptrReturn;
            }
            if( ptr[j] == filter[i]) {
                ptr[j] = '\0';
                ptr+=j+1;
                return ptrReturn;
            }
        }
    }
    return NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
    char str[200] = "This,is my,string.test";
    char *ppt = mystrtok(str,", .");
    while(ppt != NULL ) {
        cout<< ppt << endl;
        ppt = mystrtok(NULL,", ."); 
    }
    return 0;
}
0
Dipak

Für diejenigen, die diese strtok()-Funktion noch immer nicht verstehen können, werfen Sie einen Blick auf dieses pythontutor-Beispiel . Es ist ein großartiges Werkzeug, um Ihren C-Code (oder C++, Python ...) zu visualisieren.

Falls der Link gebrochen wurde, fügen Sie Folgendes ein:

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

int main()
{
    char s[] = "Hello, my name is? Matthew! Hey.";
    char* p;
    for (char *p = strtok(s," ,?!."); p != NULL; p = strtok(NULL, " ,?!.")) {
      puts(p);
    }
    return 0;
}

Credits gehen an Anders K.

0
clifer4