C 标记字符串
Posted
技术标签:
【中文标题】C 标记字符串【英文标题】:C Tokenize String 【发布时间】:2014-04-20 04:04:53 【问题描述】:我试图在保留分隔符的同时通过分隔符标记字符串。我尝试使用strtok(string, delimiters)
,但该函数不保留分隔符。例如,如果我的字符串是:
"my name < is|John >hi"
当我看到符号"space", "<", ">"
时,我想拆分。
令牌将是:
my, space, name, space, < , space, is, |, John, space, <, hi
起初,我尝试逐个字符地读取字符,直到看到一个分隔符。如果我没有看到符号,我会将读取的字符附加到它之前的字符串中。例如,对于字符串“hi|bye”。我会读“h”,读下一个字符。它是一个“i”,所以将它附加到“h”。阅读下一个符号,它是一个分隔符,所以将“hi”放入数组中,还有“|”成一个数组。重复直到完成。我遇到了这样做的问题。
这是我的代码不起作用:
int main()
char *line = "command1 | command2 command3 > command4 < command5";
do_tokenize(line);
return 0;
void do_tokenize(char *line)
char *tokenized[100];
char token[100];
int tokenCounter = 0;
int tokenLength = 0;
int i;
int newToken = 1;
int tokenNum = 0;
for(i=0; line[i] !='\0'; i++)
if(line[i] != ' ' && line[i] != '<' && line[i] != '>' && line[i] != '|')
token[tokenLength] = line[i];
tokenLength++;
newToken = 1;
else
if(newToken == 1)
token[tokenLength] = '\0';
tokenized[tokenNum] = token;
tokenLength = 0;
tokenNum++;
newToken = 0;
token[tokenLength] = line[i];
token[tokenLength+1] = '\0';
tokenized[tokenNum] = token;
tokenLength = 0;
tokenNum++;
else
token[tokenLength] = line[i];
token[tokenLength+1] = '\0';
tokenized[tokenNum] = token;
tokenLength = 0;
tokenNum++;
newToken = 0;
//end else
//end for
token[tokenLength] = '\0';
tokenized[tokenNum] = token;
tokenNum++;
//print is saying that all of tokenized[j] is the last token ie command5
int j=0;
for(j; j<tokenNum; j++)
printf("%s\n", tokenized[j]);
当我尝试打印出整个数组 (tokenized[j]) 时,它表示所有这些只是最后一个标记,"command5"
。这是在C
中完成的。
【问题讨论】:
tokenized
的所有元素都指向同一个地址,即token
,这意味着您一次又一次地使用相同的缓冲区,这就是为什么当您打印tokenized
时所得到的一切是最后一个令牌。
但是我的元素在 tokenized[tokenNum]
中,并且在我向数组中添加了一些东西之后,我正在递增 tokenNum
。而token
在我发现它是一个令牌后正在被重写。我还放了打印语句来检查令牌是否正确。
每个tokenized[tokenNum]
等于token
,而你每次都重写token
的内容,这就是问题所在。当您遍历 for
循环时,尝试打印 tokenized[tokenNum]
的值(作为地址)。
这与:int x=5; int y=x; x=3; int z=x
有何不同。 y
和z
不是都指向x
吗?我不知道如何解决这个问题。找到令牌后是否应该初始化新的token
?
这就是变量和地址的区别:复制一个变量你得到那个变量的内容(即值);复制一个地址,你只会得到那个地址,而不是那个地址的内容。
【参考方案1】:
您似乎希望标记化数组的元素指向在“行”中找到的每个标记。代码忠实地将标记的每个字符复制到 char 数组“token”。在将整个令牌加载到“令牌”中后,它会以零终止。
-
这一切都很好;然而,下一步似乎是代码存在缺陷的地方。然后将标记化数组中的下一个指针设置为指向“标记”。问题是'token'是你的工作存储,'token'的内容是为每个新的token重新构建的。
-
最后,'tokenize'数组中所有受影响的指针都指向同一个地方;具体来说,它们都指向'token'。当然,'token'的内容是最后解析的token。
-
因此,当打印出'tokenize'数组时,它们都指向'token',并且token的内容是最后解析的token(“Command5”)......
【讨论】:
【参考方案2】:这将是一个很棒的程序,可以在调试器中运行以了解它的作用以及它是如何出错的。
如果您使用某种 IDE(集成开发环境),您可能只需按下“进入”按钮即可。
如果您使用的是 gcc,那么您可以通过在 gcc 命令中添加 -g
来轻松使用 gdb:
$ gcc -g myprog.c -o myprog
$ gdb myprog
(gdb) start
Temporary breakpoint 1 at 0x4009d1
Starting program: myprog
Temporary breakpoint 1, 0x00000000004009d1 in main ()
(gdb) step
Single stepping until exit from function main,
which has no line number information.
...
【讨论】:
感谢你们编辑我的问题以使其正确。我删除了我的调试“printf”语句,以使你们的代码更清晰。将令牌放入tokenized[tokenNum]后,我打印出tokenized[tokenNum],它们都是正确的。出于某种原因,它在某处覆盖了我的标记化数组,但 tokenNum 只是增加而不是减少,所以 tokenized[0] 如何成为我字符串中的最后一个标记。所有 tokenized[] 都是“command5”。我使用 gcc,之前从未使用过 gdb。以上是关于C 标记字符串的主要内容,如果未能解决你的问题,请参考以下文章
使用 C/C++ 有效地反序列化由浮点数、标记和空行组成的字符串