关于 c:Strtok 和字符串操作问题

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 中删除 <>" 字符,然后再次解析单词字符串,则仅在单词有效时才打印。
  • 知道了。谢谢您的帮助。

以上是关于 c:Strtok 和字符串操作问题的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>