我正在从文件中读取行并对其进行标记。令牌被区分为由空格分隔或者如果它们在引号内(例如:"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;
}
答案 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
个令牌,以免溢出提供的缓冲区。