C 如何在使用strtok()后恢复字符串

C 如何在使用strtok()后恢复字符串,c,sorting,strtok,C,Sorting,Strtok,我有一个项目,在这个项目中,我需要根据每行中的第二个、第三个等单词,而不是第一个单词,对多行文本进行排序。比如说, this line is first but this line is second finally there is this line 如果你选择按第二个单词排序,它会变成 this line is first finally there is this line but this line is second (因为行在前面,所以在此之前有) 我有一个指向包含每一

我有一个项目,在这个项目中,我需要根据每行中的第二个、第三个等单词,而不是第一个单词,对多行文本进行排序。比如说,

this line is first

but this line is second

finally there is this line
如果你选择按第二个单词排序,它会变成

this line is first

finally there is this line

but this line is second
(因为行在前面,所以在此之前有)

我有一个指向包含每一行的字符数组的指针。到目前为止,我所做的是使用strtok()将每一行拆分为第二个单词,但这会将整个字符串更改为该单词,并将其存储在我的数组中。我的标记化位代码如下所示:

 for (i = 0; i < numLines; i++) {
   char* token = strtok(labels[i], " ");
   token = strtok(NULL, " ");
   labels[i] = token;
 }
编辑2:用于排序的相关代码

//Getting the line and offset
for (i = 0; i < numLines && fgets(buffer, sizeof(buffer), fp) != 0; i++) {
   labels[i].line = strdup(buffer);
   labels[i].offset = find_offset(labels[i].line, nth);
}


int n = sizeof(labels) / sizeof(labels[0]);
qsort(labels, n, sizeof(*labels), myCompare);
for (i = 0; i < numLines; i++)
  printf("%d: %s", i, labels[i].line); //Print the sorted lines


int myCompare(const void* a, const void* b) { //Compare function
  xline *xlineA = (xline *)a;
  xline *xlineB = (xline *)b;

  return strcmp(xlineA->line + xlineA->offset, xlineB->line + xlineB->offset);
}
//获取直线和偏移量
对于(i=0;iline+xlineA->offset,xlineB->line+xlineB->offset);
}

也许不要乱用
strtok()
,而是使用
strspn(),strcspn()
来解析字符串中的令牌。然后原始字符串甚至可以是
const

#include <stdio.h>
#include <string.h>

int main(void) {
  const char str[] = "this line is first";
  const char *s = str;
  while (*(s += strspn(s, " ")) != '\0') {
    size_t len = strcspn(s, " ");

    // Instead of printing, use the nth parsed token for key sorting
    printf("<%.*s>\n", (int) len, s);

    s += len;
  }
}
伪代码

int fcmp(a, b) {
  return strcmp(a->line + a->offset, b->line + b->offset);
}

size_t find_offset_of_nth_word(const char *s, n) {
  while (n > 0) {
    use strspn(), strcspn() like above
  }
}

main() {
  int nth = ...;
  xline labels[numLines];
  for (i = 0; i < numLines && fgets(buffer, sizeof(buffer), fp) != 0; i++) {
     labels[i].line = strdup(buffer);
     labels[i].offset = find_offset_of_nth_word(nth);
  }

  qsort(labels, i, sizeof *labels, fcmp);

}
int fcmp(a,b){
返回strcmp(a->line+a->offset,b->line+b->offset);
}
大小找不到第n个字的偏移量(常量字符*s,n){
而(n>0){
像上面一样使用strspn()、strcspn()
}
}
main(){
int n=。。。;
xline标签[numline];
对于(i=0;i

阅读每一行后,找到带有strspn()、strcspn()和strcspn()的
nth
标记,并将行从
“aaa bbb ccc ddd\n”
改为
“ccd ddd\naaa bbb”
,排序,然后重新排序该行


在任何情况下,都不要使用strtok()
——会丢失太多信息

我需要把绳子按原样重新组合起来。我知道strtok会将令牌转换为“\0”,但我还没有找到一种方法来恢复原始字符串

如果要保留原始字符串,最好首先避免损坏它们,尤其是避免丢失指向它们的指针。假设每行中至少有三个字,并且第二个字与第一个字和第三个字之间的每边正好有一个空格,则可以撤消
strtok()
用字符串终止符替换分隔符的操作。但是,一旦丢失整个字符串,就没有安全可靠的方法来恢复它的开头


我建议创建一个辅助数组,在其中记录每个句子的第二个单词的信息——在不破坏原始句子的情况下获得的信息——然后对辅助数组和句子数组进行联合排序。aux数组中要记录的信息可以是句子第二个单词的副本、它们的偏移量和长度,或者类似的东西。

最简单的方法是先复制一个字符串。Waring:如果你把字符串放回一起,那么
标签[i]
将不会指向一个好的子stings。确实要这样做吗?如果我复制了字符串,那么如何将其转换为新的顺序?我注意到在调用
strtok()
时使用了一个分隔符,即空格。您可以提供一个分隔符列表,但以后无法判断哪些分隔符是被空字节清除的分隔符。因此,在一般情况下,您无法判断strtok()做了什么。如果保留数据原始长度的记录,并且只使用单个分隔符,则可以安排使用分隔符替换由
strtok()
添加的空字节,从而恢复字符串。在一般情况下,你不能这样做。在标记化之前复制字符串,或者避免
strtok()
而(n>0){len=strspn(s,“”;s+=len;}
是一个无限循环。这是一个很好的答案!我目前正试图通过structs解决这个问题,但我遇到了find_offset方法的问题。你能详细说明一下吗?@nhlyoung发布你的麻烦的
查找偏移量()
代码,我看看。还有,“问题”到底是什么?它没有打印任何东西。我已经把它设置成在阅读后打印最初的前三行。像labels[i].line=strdup(buffer)一样读取每一行都很好,然后我就可以打印这些行了。但是如果我试图找到偏移量,程序就会冻结,什么也不打印。如果我对它打印的行进行注释,那么我认为查找偏移量有问题method@nhlyoung非常感谢你,我感觉我离你很近,但还有一件事。无论我将“n”改为什么,它仍然会根据每行中的第一个单词对行进行排序和打印。如果有意义的话,我需要它根据“n”字排序。我将发布相关的代码片段
#include <stdio.h>
#include <string.h>

int main(void) {
  const char str[] = "this line is first";
  const char *s = str;
  while (*(s += strspn(s, " ")) != '\0') {
    size_t len = strcspn(s, " ");

    // Instead of printing, use the nth parsed token for key sorting
    printf("<%.*s>\n", (int) len, s);

    s += len;
  }
}
<this>
<line>
<is>
<first>
typedef struct {
  char *line;
  size_t offset;
} xline;
int fcmp(a, b) {
  return strcmp(a->line + a->offset, b->line + b->offset);
}

size_t find_offset_of_nth_word(const char *s, n) {
  while (n > 0) {
    use strspn(), strcspn() like above
  }
}

main() {
  int nth = ...;
  xline labels[numLines];
  for (i = 0; i < numLines && fgets(buffer, sizeof(buffer), fp) != 0; i++) {
     labels[i].line = strdup(buffer);
     labels[i].offset = find_offset_of_nth_word(nth);
  }

  qsort(labels, i, sizeof *labels, fcmp);

}