C 标记字符串

Posted

技术标签:

【中文标题】C 标记字符串【英文标题】:C Tokenize String 【发布时间】:2014-04-20 04:04:53 【问题描述】:

我试图在保留分隔符的同时通过分隔符标记字符串。我尝试使用strtok(string, delimiters),但该函数不保留分隔符。例如,如果我的字符串是:

"my name < is|John >hi"

当我看到符号"space", "&lt;", "&gt;" 时,我想拆分。

令牌将是:

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 有何不同。 yz不是都指向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中将字符串常量转换为预处理标记

strtok() 如何将字符串拆分为 C 中的标记?

使用 C/C++ 有效地反序列化由浮点数、标记和空行组成的字符串

C++ / 类编译和字符串属性:“在 '=' 标记之前需要 `)'

c_cpp 根据空间拆分字符串并将每个标记转换为大写。

c_cpp 根据空间拆分字符串并将每个标记转换为大写。