Попытка скопировать остаток строки после символа - PullRequest
0 голосов
/ 30 марта 2019

Я пытаюсь скопировать остаток введенной пользователем строки.Всегда вводится следующее: аэропорт, 00:00, 00:00.Числа - время полета и время простоя.В моем коде я получил его, чтобы выплюнуть аэропорт, но попытка использовать strchr, чтобы найти все после первого "," - это боль.Есть ли способ, которым я могу удалить аэропорт и поместить остальные в новую строку и продолжать использовать strchr?Я должен переформатировать строки, разделенные запятыми, это цель.Конечный результат должен быть следующим: «В городе есть время полета, т.е. время в часах, и время ожидания, когда время в часах».Я не могу использовать scanf или тому подобное, так что, похоже, strchr и strcopy - мои единственные варианты.Любая помощь приветствуется.

То, что у меня сейчас есть, выдает ошибку при попытке найти символ после последнего символа "," в строке.

Правила назначения: не используйте strtok (), никакой связанный со scanfфункции, любые функции, выполняющие токенизацию строковых данных.

int main()
{
    int counter = 0;
    int flightTimeNum = 0;
    char userInput[81] ="";
    char userInputNew[81] = "";
    char cityNew[20] = "";
    char flightTime[20] = "";
    char layOverTime[20] = "";


    fgets(userInput, 81, stdin);
    char *city;
    char *flight;
    char *layover;

    city = strchr(userInput, ',');
    strncpy(cityNew, userInput, city - userInput);
    printf("%s\n" ,cityNew);

    layover = strrchr(userInput, ',');
    strncpy(layOverTime, userInput, layover - userInput);
    printf("%s\n", layOverTime);

    printf("Press ENTER key to Continue\n");
    getchar();

}

Ответы [ 4 ]

3 голосов
/ 30 марта 2019

Если вы хотите использовать strchr, вы можете подумать о создании подстрок, заменив каждую ',' на нулевой терминатор \0, а затем установите указатели на каждую подстроку на основе длины предыдущей строки.

В качестве альтернативы, вы можете пройти через строку, накапливая символы, пока не достигнете ,, а затем завершить буфер и начать накапливать следующую часть строки в следующем буфере и повторять, пока не достигнете нулевого терминатораuserInput.

Пример первого подхода, обратите внимание, вы должны проверить, что вы смогли создать ожидаемое количество подстрок и т. Д. На случай, если пользователь введет недопустимые данные.

// NULL terminate each substring
char *p = userInput;    // Point to the beginning of the string
for(;;) {
    p = strchr(p, ','); // Find first ',' starting from 'p'
    if (!p) break;      // If not found break out of loop
    *p = '\0';          // otherwise replace ',' with a null terminator
    ++p;                // move pointer 'p' to the next character
}

// Setup pointers to each substring
city = userInput; 
flight = city + strlen(city) + 1;
layover = flight + strlen(flight) + 1;
2 голосов
/ 30 марта 2019

Пока вы можете анализировать информацию из каждой строки с помощью указателя и strchr (или просто перемещая указатель вниз по вашему буферу), когда имеете дело с отформатированным вводом *1003*, используя Функция форматированного ввода , как sscanf, может очень помочь.

Давайте посмотрим на оба. В вашем вопросе вы хотите прочитать с fgets (хорошо), а затем найти первую запятую, а затем скопировать оставшуюся часть строки в новый буфер. Пока все хорошо. Единственное предостережение: когда вы найдете первую запятую, вы все равно должны продвигать указатель от запятой, пропуская все пробелы, пока не достигнете первого символа в оставшуюся часть времени (остаток строки).

Простой подход, который просто выводит остаток строки после первой запятой, пропуская любые промежуточные пробелы, может быть:

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

#define MAXC 1024   /* if you need a constant, define one (or more) */

int main (void) {

    char buf[MAXC];

    while (fgets (buf, MAXC, stdin)) {      /* read with fgets */
        char *p;
        buf[strcspn (buf, "\r\n")] = 0;     /* trim '\n' from end */
        if ((p = strchr (buf, ','))) {      /* find 1st ',' */
            do
                p++;                    /* advance pointer */
            while (*p && isspace (*p)); /* to end or 1st non-whitespace */
        }
        printf ("rest of string: '%s'\n", p);   /* output rest of line */
    }
}

( примечание: при объявлении констант, не экономить на размере буфера.)

Пример входного файла

$ cat dat/airport_times.txt
KOCH, 01:01, 01:51
KAXX, 03:50, 05:40
KADS, 07:40, 09:30

Пример использования / Вывод

$ ./bin/airport_gettimes <dat/airport_times.txt
rest of string: '01:01, 01:51'
rest of string: '03:50, 05:40'
rest of string: '07:40, 09:30'

Теперь давайте рассмотрим использование fgets для функции чтения и функции форматированного ввода sscanf для анализа всех необходимых значений из каждой строки. (или вы можете использовать fscanf, чтобы сделать это за один вызов, но лучше использовать fgets, а затем sscanf, чтобы (1) убедиться, что вы используете всю строку данных, и (2) можете независимо проверить чтение и анализ значений.

Подход аналогичен, читается с fgets, но затем вместо поиска первой запятой с strchr просто используйте sscanf для считывания ИКАО, времени прибытия и времени отправления в отдельные буферы в одном вызове. ВСЕГДА проверяйте ВОЗВРАТ любой из функций scanf, чтобы обеспечить ожидаемое количество преобразований.

Забегая вперед, давайте не будем просто использовать три отдельных и не связанных буфера. Вместо этого давайте объявим struct для хранения всех трех буферов icao, ariv & dept. Таким образом, если вы читаете несколько записей в память, вы можете просто объявить массив struct и прочитать / проанализировать все значения для последующего пользователя. (массив оставлен вам)

Простой пример здесь может быть:

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

#define MAXC 1024   /* if you need a constant, define one (or more) */
#define ICAO    6   /* will work for ICAO and time buffer lengths */

typedef struct {
    char icao[ICAO],
        ariv[ICAO],
        dept[ICAO];
} flight_t;

int main (void) {

    char buf[MAXC];

    while (fgets (buf, MAXC, stdin)) {      /* read with fgets */
        flight_t flt = { .icao = "" };      /* declare struct */
        /* separate all value in line into struct, validating return */
        if (sscanf (buf, "%5[^,], %5[^,], %5[^,]", 
                    flt.icao, flt.ariv, flt.dept) == 3)
            /* if sscanf succeeds, output (or use) the values */
            printf ("%s  %s (arrival)  %s (departure)\n",
                    flt.icao, flt.ariv, flt.dept);
    }
}

( примечание: как используется модификатор field-width перед каждым символьным классом спецификатор преобразования для защиты границ массива для каждого буфера с "%5[^,], %5[^,], %5[^,]" . Если у вас есть вопросы по поводу строки формата, просто спросите.)

Тот же файл ввода.

Пример использования / Вывод

$ ./bin/airport_parsetimes <dat/airport_times.txt
KOCH  01:01 (arrival)  01:51 (departure)
KAXX  03:50 (arrival)  05:40 (departure)
KADS  07:40 (arrival)  09:30 (departure)

Преимущество здесь в том, что теперь все значения координируются как один объект, но сохраняются независимо, поэтому вы можете получить доступ к любому из значений icao, ariv или dept по мере необходимости, в то время как в случае массива struct, сохраняя возможность сортировки массива по любому члену структуры, сохраняя при этом связь icao, времени прибытия и отправления.

Существует множество способов собрать кусочки головоломки вместе. Следующим шагом будет динамическое выделение вашего массива struct и realloc по мере необходимости, чтобы вы могли читать неизвестное и неограниченное количество записей (вплоть до физической памяти вашего компьютера). Однако два подхода: (1) анализировать буфер с помощью указателя или (2) использовать форматированную функцию ввода, покрывают большинство случаев. Все, что осталось, строится на этом фундаменте по желанию.

0 голосов
/ 30 марта 2019

strchr() вернет указатель на символ, означающий, что он продвинется в строке.Вы можете использовать ее как новую строку для дальнейших операций:

char str[] = "airport, 00:00, 00:00.";
char* rem = strchr(str, ','); // rem is now ", 00:00, 00:00."
rem += 2; // rem is now "00:00, 00:00."
rem = strchr(rem, ','); // rem is now ", 00:00, 00:00."
rem += 2; // rem is now "00:00."
*strchr(rem, '.') = 0; // rem is now "00:00" (dot removed)

Конечно, вы должны проверить возврат NULL, когда символ не существует ...

РЕДАКТИРОВАТЬ:Слишком заманчиво представить мою собственную реализацию, чтобы вы увидели, как работают указатели в C:

char str[] = "airport, 00:00, 00:00.";
char* city = str; // "airport, 00:00, 00:00."
char* departure = strchr(str, ','); // ", 00:00, 00:00."
char* arrival = strchr(departure+1, ','); // ", 00:00."
// Clean up
*departure = 0; // city is now "airport"
departure += 2; // depature is now "00:00, 00:00."
*arrival = 0; // departure is now "00:00"
arrival += 2; // arrival is now "00:00."
*strchr(arrival, '.') = 0;  // arrival is now "00:00"

Опять же, если это пользовательский ввод, вы должны проверить, что strchr() возвращает NULLпотому что это произойдет .

0 голосов
/ 30 марта 2019

Вот альтернативное решение, использующее функцию для поиска первой цифры.

Это будет работать лучше, чем strstr (), если вы знаете, что строка, которая вас интересует, начинается с цифры.

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

char* find_digit(char* string)
{
  while(*string != '\0') {
    char ch = *string;

    if(*string >='0' && *string <= '9') {
      return string;
    }
    string++;

  }
}
int main()
{
  char str[] = "airport, 00:00, 00:00.";

  char* ret = find_digit(str);

  char* remainder = ret + strlen(needle);

  printf("Remainder is: %s\n",remainder);

  return 0;
}
...