使用strtok()后如何还原字符串

时间:2019-01-30 21:53:28

标签: 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

(因为行在此之前)

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

 for (i = 0; i < numLines; i++) {
   char* token = strtok(labels[i], " ");
   token = strtok(NULL, " ");
   labels[i] = token;
 }

这将给我每一行的第二个单词,因为我两次调用strtok。然后,我对这些单词进行排序。 (行,在这里)但是,我需要将字符串以其原始形式放回原处。我知道strtok将标记转换为“ \ 0”,但是我还没有找到一种方法来找回原始字符串。

我确定答案就在于使用指针,但是我对下一步到底需要做什么感到困惑。

我应该提到我正在读取输入文件中的行,如下所示:

for (i = 0; i < numLines && fgets(buffer, sizeof(buffer), fp) != 0; i++) {
  labels[i] = strdup(buffer);

编辑:我的find_offset方法

size_t find_offset(const char *s, int n) {
  size_t len;
  while (n > 0) {
     len = strspn(s, " ");
     s += len;
  }

  return len;
} 

编辑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);
}

2 个答案:

答案 0 :(得分:4)

使用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;
  }
}

输出

<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);

}

读取每一行后,用nth找到strspn(), strcspn()令牌,然后将行从"aaa bbb ccc ddd \n"改成"ccd ddd \naaa bbb ",进行排序,然后对行重新排序。


在所有情况下,请勿使用strtok()-丢失太多信息。

答案 1 :(得分:1)

  

我需要将字符串以其原始形式放回原处。我知道strtok将标记转换为“ \ 0”,但是我还没有找到一种方法来找回原始字符串。

Far 最好是避免保留原始字符串,尤其是避免丢失指向它们的指针。只要可以安全地假设每行中至少有三个单词,并且第二行与第一行和第三行之间的每一边都恰好隔开一个空格,则可以撤消strtok()的定界符替换为字符串终止符。但是,一旦丢失整个字符串,就没有安全可靠的方法可以恢复。

我建议创建一个辅助数组,在其中记录有关每个句子第二个单词的信息(在不损坏原始句子的情况下获得),然后将辅助数组和句子数组进行共同排序。要在aux数组中记录的信息可以是句子第二个单词的副本,它们的偏移量和长度或类似的内容。