programing

스트르토크()는 어떻게 그 문자열을 C에서 토큰으로 나누는가?

prostudy 2022. 5. 16. 21:00
반응형

스트르토크()는 어떻게 그 문자열을 C에서 토큰으로 나누는가?

의 작업을 설명해 주시오.strtok() 으로 쪼개어 있다매뉴얼에 따르면 끈을 토큰으로 쪼갠다고 되어 있다.나는 매뉴얼로 그것이 실제로 무엇을 하는지 이해할 수 없다.

나는 시계를 추가했다.str그리고*pch루프가 처음 발생했을 때 작동하는지 확인하기 위해str"이것"에 불과했다.아래 나온 출력이 화면에 어떻게 출력되었는가?

/* 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;
}

출력:

문자열 "- 샘플 문자열"을 토큰으로 분할:
이것a견본을 뜨다끈을 매다

strtok 런타임 함수는 다음과 같이 작동한다.

처음 strtok을 호출할 때 토큰화하려는 문자열을 제공하십시오.

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

위의 문자열 공간은 단어 사이의 구분이 좋은 것 같으니, 다음을 사용하십시오.

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

지금 일어나는 일은 스페이스 문자가 발견될 때까지 's'를 검색하고 첫 번째 토큰을 반환(' this')하며 p는 해당 토큰(문자열)을 가리킨다.

다음 토큰을 얻고 동일한 문자열 NULL을 계속하려면 strtok이 이전에 전달된 문자열에 대한 정적 포인터를 유지하므로 첫 번째 인수로 전달하십시오.

p = strtok(NULL," ");

p 이제 ' is'를 가리킨다.

그리고 더 이상 공백을 찾을 수 없을 때까지, 마지막 문자열은 마지막 토큰 '스트링'으로 반환된다.

더 편리하게 모든 토큰을 인쇄할 수 있다.

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

편집:

이 반환을을 from from from 에서 반환된 .strtok토큰을 다른 버퍼에 복사해야 한다(예: strdup(p);원래 문자열(안쪽에 있는 정적 포인터에 의해 표시됨) 이후strtok은 토큰을 는 토큰을 반환하기 위해 반복 간에 수정된다.

strtok문자열에서 사용 가능한 다음 토큰을 가리키는 정적 내부 참조를 유지하며, NULL 포인터를 전달하면 내부 참조에서 작동한다.

이 때문이다.strtok새로운 포인터를 통과하면 오래된 내부 참조가 삭제된다.

strtok()문자열을 토큰으로 나눈다. 즉, 구분 기호 중 하나에서 다음 구분 기호로 시작하는 것이 하나의 토큰이 된다.당신의 경우, 출발 토큰은 "-"에서, 그리고 다음 공간 "로 끝날 것이다.그러면 다음 토큰은 " "에서 시작하여 ","로 끝난다. 여기 출력물로 "This"가 나온다.마찬가지로 나머지 문자열은 우주에서 우주로 토큰으로 분할되어 마침내 마지막 토큰을 ""에 끝맺는다.

아직도 이해하는데 어려움을 겪고 있는 분들을 위해서.strtok()함수, 이 비단뱀의 예를 보십시오. 그것은 당신의 C(또는 C++, Python...) 코드를 시각화하는 데 좋은 도구 입니다.

링크가 끊어진 경우 다음 위치에 붙여넣으십시오.

#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;
}

학점은 안데르스 K에게 돌아간다.

스트르톡은 문자열을 토큰화한다. 즉, 문자열을 일련의 하위 문자열로 변환한다.

그것은 이러한 토큰(또는 서브스트링)을 구분하는 구분 기호를 검색함으로써 그렇게 한다.그리고 구분 기호를 지정한다.당신의 경우, ' 또는 '', '.' 또는 '-'를 구분자로 하고 싶다.

이러한 토큰을 추출하는 프로그래밍 모델은 메인 문자열과 구분 기호 집합을 손으로 직접 만드는 것이다.그리고 당신은 그것을 반복해서 부르고, 그때마다 스트르톡은 찾은 다음 토큰을 돌려줄 것이다.주 문자열 끝에 도달할 때까지, null을 반환할 때.또 다른 규칙은 문자열을 처음에만 전달하고 이후 시간에는 NULL을 전달하는 것이다.이것은 당신이 새로운 문자열로 토큰화의 새 세션을 시작하거나 이전 토큰화 세션에서 토큰을 검색하는 경우 스트르톡을 알려주는 방법이다.strtok은 토큰화 세션의 상태를 기억한다는 점에 유의하십시오.그리고 이러한 이유로 재입고되거나 스레드가 안전하지 않다(대신 strtok_r을 사용해야 한다).또 하나 알아야 할 것은 그것이 실제로 원래의 줄을 수정한다는 것이다.그것은 그것이 찾은 구분자에 대해 '\0'이라고 쓴다.

스트르톡을 굴복하게 하는 한 가지 방법은 다음과 같다.

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);
}

결과:

this
is
the
string
I
want
to
parse

이것이 내가 스트로크를 구현한 방법이다. 그렇게 좋지는 않지만, 2시간 동안 작업한 후에야 비로소 효과가 있었다.그것은 여러 개의 구분 기호를 지원한다.

#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;
}

O(n^2) 대신 O(n)를 의미하는 구분 기호에 대해 해시 테이블을 사용하는 구현(여기 코드에 대한 링크가 있음):

#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;
}

처음 호출할 때 토큰화할 문자열을strtok 다짜고짜를 NULL그 기능을 위해, 그것이 non을 반환하는 한.NULL포인터

strtok함수는 당신이 부를 때 당신이 처음 제공한 문자열을 기록한다. (다중 스레드 어플리케이션에 정말로 위험한 것)

스트르톡은 입력 문자열을 수정한다.원래 문자열의 비트를 토큰으로 반환하도록 null 문자('\0')를 삽입한다.사실 strtok 메모리를 할당하지는 않다.상자 순서대로 줄을 그으면 더 잘 이해할 수 있을 거야.

방법을 이해하려면strtok()작용한다. 우선 정적 변수가 무엇인지 알아야 한다.이 링크는 그것을 꽤 잘 설명해 준다.

운영의 열쇠strtok()마지막 분리기 위치를 보존하는 거야 (그래서)strtok()로 호출될 때 전달되는 바로 그 원본 문자열을 계속 구문 분석한다.null pointer연이은 호출로)..

내 좀 봐 봐 를 보아라.strtok()실행(부름)라고 하는zStrtok()에 의해 제공되는 기능과는 상당히 다른 기능을 가지고 있다.strtok()

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;
}

그리고 여기 예시가 있다.

  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)

그 코드는 zString이라고 불리는 Github에 내가 관리하는 문자열 처리 라이브러리에서 나온 것이다.코드를 확인하거나 기여하십시오. https://github.com/fnoyanisi/zString

strtok매개 변수 자체를 변경하지 않음(str. (로컬 정적 변수에) 포인터를 저장한다.그런 다음 매개 변수를 다시 전달하지 않고 후속 호출에서 해당 매개 변수가 가리키는 것을 변경할 수 있다. (그리고 작업을 수행하는 데 필요한 방식으로 유지한 포인터를 전진시킬 수 있다.)

POSIX 페이지에서:

이 기능은 통화 사이의 현재 문자열 위치를 추적하기 위해 정적 저장장치를 사용한다.

스레드 세이프 변종이 있다().strtok_r 이런 종류의 마법을 부리지 않는다.

strtok()는 당신이 마지막으로 떠난 정적 변수에 포인터를 저장하였습니다, 그래서 우리가 null을 통과할 때 그것의 두 번째 통화에, strtoktok는 정적 변수로부터 포인터를 얻습니다.

만약 당신이 같은 문자열 이름을 제공한다면, 그것은 처음부터 다시 시작된다.

게다가 스트르토크()는 파괴적이다. 즉, 오르골 문자열을 변경하기 때문에 항상 오르골 문자열을 복사해야 한다.

strtok()을 사용하는 또 다른 문제는 정적 변수에 주소를 저장함에 따라 strtok()을 호출하는 다중 스레드 프로그래밍에 두 번 이상 오류가 발생한다는 것이다.이를 위해 strtok_r()를 사용하십시오.

strtok은 두 번째 인수의 문자를 NULL로 대체하며 NULL 문자는 문자열의 끝이기도 하다.

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

새 줄만 인쇄하면 해당 토큰을 찾는 경우 Char 어레이를 스캔할 수 있고 그렇지 않으면 Char를 인쇄하십시오.

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

int main()
{
    char *s;
    s = malloc(1024 * sizeof(char));
    scanf("%[^\n]", s);
    s = realloc(s, strlen(s) + 1);
    int len = strlen(s);
    char delim =' ';
    for(int i = 0; i < len; i++) {
        if(s[i] == delim) {
            printf("\n");
        }
        else {
            printf("%c", s[i]);
        }
    }
    free(s);
    return 0;
}

그래서, 이것은 이 주제를 더 잘 이해하도록 돕는 코드 조각이다.

토큰 인쇄

과제: 문장이 주어지면 s, 문장의 각 단어를 새 줄에 인쇄한다.

char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
//logic to print the tokens of the sentence.
for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
    printf("%s\n",p);
}

입력: How is that

결과:

How
is
that

설명:그래서 여기서는 "sttok()" 기능이 사용되며, 별도 선으로 토큰을 인쇄하기 위해 루프(loop)

이 함수는 매개 변수를 '끈'과 '차단점'으로 잡고 그 중단점에서 문자열을 끊고 토큰을 형성한다.이제, 그 토큰들은 'p'에 저장되어 인쇄에 더 많이 사용된다.

strtok구분 기호를 다음으로 바꾸기'\0' 문자열

코드

#include<iostream>
#include<cstring>

int main()
{
    char s[]="30/4/2021";     
    std::cout<<(void*)s<<"\n";    // 0x70fdf0
    
    char *p1=(char*)0x70fdf0;
    std::cout<<p1<<"\n";
    
    char *p2=strtok(s,"/");
    std::cout<<(void*)p2<<"\n";
    std::cout<<p2<<"\n";
    
    char *p3=(char*)0x70fdf0;
    std::cout<<p3<<"\n";
    
    for(int i=0;i<=9;i++)
    {
        std::cout<<*p1;
        p1++;
    }
    
}

출력

0x70fdf0       // 1. address of string s
30/4/2021      // 2. print string s through ptr p1 
0x70fdf0       // 3. this address is return by strtok to ptr p2
30             // 4. print string which pointed by p2
30             // 5. again assign address of string s to ptr p3 try to print string
30 4/2021      // 6. print characters of string s one by one using loop

문자열을 토큰화하기 전에

나는 어떤 ptr(p1)에 s 문자열 주소를 할당하고 그 ptr을 통해 문자열을 인쇄하려고 시도했고 전체 문자열이 인쇄된다.

토큰화 후

strtok은 문자열 s의 주소를 ptr(p2)에 반환하지만, ptr을 통해 문자열을 인쇄하려고 할 때 "30"만 인쇄할 뿐 전체 문자열을 인쇄하지 않았다.그러니 틀림없이strtok is not just returning adress but it is placing '\0' character where delimiter is present.

교차 점검

1.

나는 다시 어떤 ptr(p3)에 문자열의 주소를 할당하고, 구분 기호의 '\0'으로 문자열을 토큰화하는 동안 문자열을 "30"으로 인쇄하려고 한다.

2.

참고 항목루프를 통해 문자열을 문자로 인쇄할 때 첫 번째 구분 기호가 '\0'으로 바뀌므로 ''이 아닌 빈 공간을 인쇄할 수 있음

참조URL: https://stackoverflow.com/questions/3889992/how-does-strtok-split-the-string-into-tokens-in-c

반응형