【问题标题】:How to restore string after using strtok()使用 strtok() 后如何恢复字符串
【发布时间】:2019-01-30 21:53:27
【问题描述】:

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

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 两次。然后我对这些词进行排序。 (line, this, there) 但是,我需要将字符串以原始形式重新组合在一起。我知道 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);
}

【问题讨论】:

  • 最简单的做法是先复制字符串。
  • Waring:如果你把字符串重新组合在一起,那么labels[i] 将不会指向一个好的子字符串。你确定要这个吗?
  • 如果我复制了字符串,那么我怎样才能让它进入新的顺序?
  • 我注意到您在调用strtok() 时使用了一个分隔符,即一个空格。您可以提供一个定界符列表,但您以后无法分辨出这些定界符中的哪一个是被空字节删除的定界符。因此,在一般情况下,您无法分辨 strtok() 做了什么。如果您记录了数据的原始长度并且只使用了一个分隔符,那么您可以安排将strtok() 添加的空字节替换为分隔符,从而恢复字符串。在一般情况下,您不能这样做。在标记之前复制字符串,或避免使用strtok()
  • while (n &gt; 0) { len = strspn(s, " "); s += len; } 是一个无限循环。

标签: c sorting strtok


【解决方案1】:

也许与其混淆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() - 丢失太多信息。

【讨论】:

  • 这是一个很好的答案!我目前正在尝试通过结构来解决它,但我遇到了 find_offset 方法的问题。你能详细说明一下吗?
  • @nhlyoung 发布您的麻烦find_offset() 代码,我会看到。还有究竟是什么“问题”?
  • 它不打印任何东西。我将其设置为在阅读原始前三行后打印它们。像 labels[i].line = strdup(buffer) 这样读取每一行都可以正常工作,然后我可以打印这些行。但是如果我试图找到偏移量,程序就会冻结并且什么也不打印。如果我注释掉它会打印出来,所以我认为这是 find offset 方法的问题
  • @nhlyoung infinite loop
  • 非常感谢,我觉得我已经很接近了,但还有一件事。无论我将“nth”更改为什么,它仍然会根据每行中的第一个单词对行进行排序和打印。如果有意义的话,我需要它根据“第 n 个”词进行排序。我贴出相关代码sn-ps
【解决方案2】:

我需要将字符串以原始形式重新组合在一起。我知道 strtok 将标记转换为 '\0',但我还没有找到一种方法来取回原始字符串。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多