在没有strtok的情况下对一行进行标记

时间:2014-06-03 12:03:42

标签: c token tokenize

我正在从文件中读取行并对其进行标记。令牌被区分为由空格分隔或者如果它们在引号内(例如:"to ken")。

我写了一个代码,但我的指针有问题。我不知道如何从一行存储令牌,或者更确切地设置指针。

还有人建议我在每个令牌后面加上一个0"识别"所以我知道它何时结束,并且我只在char *tokens[]存储指向标记开头的指针。

我目前的代码:

char *tokens[50];
int token_count;

int tokenize(char *line){
    token_count = 0;
    int n = 0;          

    while(line[n] != NULL || line[n] != '\n'){
        while(isspace(line[n++]));
        if(line[n] == '"'){
            while(line[++n] != '"' || line[n] != NULL){
                  /* set tokens[n] */
            }
        }
        else{
            while(!isspace(line[n++])){
                  /*set tokens[n] */
            }

        }

        n++;
    }

    tokens[token_count] = 0;

}

1 个答案:

答案 0 :(得分:1)

您使用字符串base line和索引n来逐步增加n

while (str[n] != '\0') n++;

如果使用指针,您的任务可能会更容易:

while (*str != '\0') str++;

然后,您可以在读取令牌之前用指针的值表示您的令牌,即当您点击引号或非空格时。这为你提供了令牌的开始。

令牌的长度怎么样?在C中,字符串是字符数组,以空字符结尾。这意味着,您的令牌包含整行的其余部分,因此包含所有后续令牌。您可以在每个令牌之后放置'\0',但这有两个缺点:它不适用于只读字符串文字,并且根据您的令牌语法,它并不总是可行的。例如,字符串a"b b"c应该可以解析为三个标记a"b b"c,但在标记之后放置空字符会破坏标记过程。

另一种方法是将标记存储为指向起始字符和长度的指针。这些标记不再以空值终止,因此如果要将它们与标准C字符串函数一起使用,则必须将它们写入临时缓冲区。

这是一种方法。

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

struct token {
    const char *str;
    int length;
};

int tokenize(const char *p, struct token tk[], int n)
{
    const char *start;
    int count = 0;   

    while (*p) {
        while (isspace(*p)) p++;
        if (*p == '\0') break;

        start = p;
        if (*p == '"') {
            p++;
            while (*p && *p != '"') p++;
            if (*p == '\0') return -1;        /* quote not closed */            
            p++;
        } else {            
            while (*p && !isspace(*p) && *p != '"') p++;
        }

        if (count < n) {
            tk[count].str = start;
            tk[count].length = p - start;
        }
        count++;
    }

    return count;
}

void token_print(const struct token tk[], int n)
{
    int i;

    for (i = 0; i < n; i++) {
        printf("[%d] '%.*s'\n", i, tk[i].length, tk[i].str);
    }
}

#define MAX_TOKEN 10

int main()
{
    const char *line = "The \"New York\" Stock Exchange";
    struct token tk[MAX_TOKEN];
    int n;

    n = tokenize(line, tk, MAX_TOKEN);
    if (n > MAX_TOKEN) n = MAX_TOKEN;
    token_print(tk, n);    

    return 0;
}

每个令牌的开头都保存在本地变量中,并在扫描完成后分配给令牌。当p指向令牌后面的字符时,表达式为:

p - start

给你长度。 (这称为指针算法。)例程扫描所有令牌,但它只分配最多n个令牌,以免溢出提供的缓冲区。