Как восстановить строку после использования strtok () - PullRequest
0 голосов
/ 31 января 2019

У меня есть проект, в котором мне нужно отсортировать несколько строк текста на основе второго, третьего и т. Д. Слова в каждой строке, а не первого слова.Например,

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

Это даст мне второе слово в каждой строке, так как я дважды вызывал 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 голосов
/ 31 января 2019

Мне нужно собрать строку обратно в ее первоначальном виде.Я знаю, что strtok превращает токены в '\ 0', но я еще не нашел способ вернуть исходную строку.

Far лучше было бы избежатьповреждение оригинальных строк в первую очередь, если вы хотите сохранить их, и особенно, чтобы не потерять указатели на них.При условии, что можно с уверенностью предположить, что в каждой строке по крайней мере три слова и что второе отделено от первого и третьего ровно одним пробелом с каждой стороны, вы можете отменить замену strtok() разделителей символами конца строки,Однако не существует безопасного или надежного способа восстановить начало всей строки, как только вы ее потеряете.

Я предлагаю создать вспомогательный массив, в который вы записываете информацию о втором слове каждого предложения - полученную безповреждение оригинальных предложений - и затем совместная сортировка вспомогательного массива и массива предложений.Информация, которая должна быть записана в массив aux, может быть копией второго слова предложения, его смещений и длин или что-то подобное.

0 голосов
/ 31 января 2019

Возможно, вместо того, чтобы связываться с 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() - слишком много информации потеряно.

...