Strtok and String manipulation issues
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #define DELIMS"!"#$%&()|'*+,?/:;<=>@[\\092]^_{}~\\177"
void getFileLine (FILE *fp )
{
char *word , *ptr ;
int tokennum , count ;
char buffer [100];
while(!feof(fp ))
{
(fgets(buffer , 100, fp ));
ptr = buffer ;
for(tokennum = 1; word = strtok(ptr , DELIMS );ptr = NULL , tokennum ++)
{
word = strtok(ptr , DELIMS );
printf("%s\
", word );
}
}
} |
所以我传入了一个包含示例程序的文件。我的工作是删除一些分隔符并将代码中的每个单词传递到树中。
虽然我不在树部分,只是在努力按照我想要的方式操纵字符串,但我遇到了一些问题。
所以,当我从 .txt 文件中读取行时,我得到了我想要的部分内容。 .txt 的前几行如下:
1 2 3 4 5 6
| #include"stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FLUSH while( getchar()!= '\
') |
现在,在它运行完我的代码后,它变成了:
1 2 3 4 5
| include
include
include
include
define FLUSH while |
" 和 <> 中的单词被删除,因为它们是一些分隔符。
我遇到的问题出在 define FLUSH while 部分。当一行作为多个不是分隔符的单词时,我希望每个单词单独显示,从而输出:
1 2 3 4 5 6 7
| include
include
include
include
define
FLUSH
while |
如您所见,define FLUSH while 现在将每个单词放在单独的行上。
我认为制作 ptr=NULL 会导致 strtok 重复使用该行直到它到达末尾,但是我再次遇到了一些麻烦。任何建议/帮助都会很棒。谢谢。
- DELIMS 定义为什么?
-
@TomCarpenter 对此感到抱歉,已添加到代码中。
-
您知道 strtok 使用 NULL 作为第一个参数来继续标记当前缓冲区(在您的情况下,每行读取),对吗?
-
@WhozeCraig所以设置ptr = null,不应该继续使用同一行......这就是为什么我对为什么没有分开 define FLUSH while 感到困惑......
-
您有两个级别的操作:首先,您读取行,然后将这些行标记化,因此在解析行时,只要获得标记,就必须调用 strtok。仅在第一次调用时传递行指针。
-
是的,它应该,但每次迭代它也会调用 strtok 两次,我不确定你想要从你的描述中得到什么。我认为您至少应该从循环内部删除对 strtok 的调用。
-
请将 while(!feof(fp)) ... 替换为 while (fgets(buffer, 100, fp)) ...:您应该使用读取调用的返回值来确定输入是否已用完。
-
@MOehm 更改该 while 语句会导致一些问题....
-
@Bryan So 执行未经检查的 IO 操作。您假设 fgets 有效,并且在发生错误而不是 eof 条件时,您的外部 while 将永远不会终止。请参阅此处为什么将 feof 作为循环条件几乎总是错误的。
-
@Bryan:WhozCraig 已经在这里向您指出了相关问题。当 fgets 遇到文件末尾时,它会返回 NULL 并且未指定 buffer 的内容,很可能它们只是保持不变。你永远不会检查那个条件,所以你最终会处理最后一行两次。 feof 和它的表亲 ferror 是事后分析函数,它们告诉您是文件结束还是错误导致读取结束。
问题在于您定义 for 循环的方式:
这是代码的简化片段:
1 2 3 4 5 6
| for (; word = strtok(ptr , DELIMS );ptr = NULL )
{
word = strtok(ptr , DELIMS );
printf("%s\
", word );
} |
这相当于是:
1 2 3 4 5 6 7
| while(word = strtok(ptr , DELIMS ))
{
word = strtok(ptr , DELIMS );
printf("%s\
", word );
ptr = NULL ;
} |
注意你如何在每次迭代中调用 strtok 两次,但只打印一次?这意味着您将丢失所有其他令牌。
此外,您还没有将 (空格) 添加到令牌列表中,因此它不会在空格上拆分。
- 因此,如果 delims 现在是:#define DELIMS"!\"#$%&()|'*+,?/:;<=>@[\\092]^_{}~\\177\\040\\t" 并删除 strtok,应该会有所帮助
-
@Bryan,您可以使用 \\040 或只放一个空格。例如#define DELIMS"!\"#$%&()|'*+,?/:;<=>@[\\092]^_{}~\\177\\t"
-
好吧,跳过是帮助之王......像 stdio.h 这样的定界符应该被删除并且不会显示/添加到树中......我的错我应该在一开始就说明这一点
-
@Bryan 这比使用 strtok 更复杂。您必须添加自己的解析来删除由 <> 或 "" 包围的任何内容。如果从 delim 中删除 <>\" 字符,然后再次解析单词字符串,则仅在单词有效时才打印。
-
知道了。谢谢您的帮助。