Скажем, у меня есть текстовый файл, как это:
Пользователь: John
Устройство: 12345
Дата: 12.12.12
РЕДАКТИРОВАТЬ:
У меня есть код для успешного поиска слова и отображения информации после этого слова. Однако, когда я пытаюсь отредактировать код для поиска 2 или 3 слов и отображения информации после них вместо одного слова, я не могу заставить его работать. Я попытался добавить коды в один и тот же цикл while и создать новый цикл while для другого слова, но оба они не работают. Должно быть что-то, что я делаю неправильно / не делаю.
Пожалуйста, совет, спасибо!
Вот мой код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char file[100];
char c[100];
printf ("Enter file name and directory:");
scanf ("%s",file);
FILE * fs = fopen (file, "r") ;
if ( fs == NULL )
{
puts ( "Cannot open source file" ) ;
exit( 1 ) ;
}
FILE * ft = fopen ( "book5.txt", "w" ) ;
if ( ft == NULL )
{
puts ( "Cannot open target file" ) ;
exit( 1 ) ;
}
while(!feof(fs)) {
char *Data;
char *Device;
char const * rc = fgets(c, 99, fs);
if(rc==NULL) { break; }
if((Data = strstr(rc, "Date:"))!= NULL)
printf(Data+5);
if((Data = strstr(rc, "Device:"))!=NULL)
printf(Device+6);
}fclose ( fs ) ;
fclose ( ft ) ;
return 0;
}
Хорошо, надеюсь, я смогу очистить это время. Извините, если я иногда путаюсь, но мой английский не самый лучший.
Я объясню реализацию внутри комментариев:
#define BUFFSIZE 1024
int main()....
char buff[BUFFSIZE];
char delims[] = " "; /*Where your strtok will split the string*/
char *result = NULL;
char *device; /*To save your device - in your example: 12345*/
char *date; /*To save the date*/
int stop = 0;
fp = fopen("yourFile", "r");
while( fgets(buff, BUFFSIZE,fp) != NULL ) /*This returns null when the file is over*/
{
result = strtok( buff, delims ); /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/
while(result != NULL){ /*Strtok returns null when finishes reading the given string*/
if(strcmp(result,"Device")==0){ /*strcmp returns 0 if the strings are equal*/
result = strtok(NULL, delims); /*this one gets the 12345*/
device = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
strcpy(device, result); /*Now, device is "12345"*/
}
/*Here you do the same but for the string 'Date'*/
if(strcmp(result,"Date")==0){ /*strcmp returns 0 if the strings are equal*/
result = strtok(NULL, delims); /*this one gets the 12345*/
date = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
strcpy(date, result); /*Now, device is "12/12/12"*/
}
/*And you can repeat the if statement for every string you're looking for*/
result = strtok(NULL,delims); /*Get the next token*/
}
}
/*No strtok necessary here */
...
Надеюсь это поможет.
fgetc
возвращает целочисленное значение, которое является символом и повышается до int.
Я полагаю, вы имели в виду fgets
которая читает целую строку, но вам нужно зарезервировать для нее память, например:
#define BUF 100
...
char c[BUF];
fgets(c, BUF, fs);
В вашем коде есть пара проблем: в основном он никогда не компилируется.
Вот версия с небольшими очистками, которая по крайней мере компилируется:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char file[100];
char c[100];
printf ("Enter file name and directory:");
scanf ("%s",file);
FILE * fs = fopen (file, "r") ;
if ( fs == NULL ) {
puts( "Cannot open source file" ) ;
exit(1 ) ;
}
while(!feof(fs)) {
char *Data;
char const * rc = fgets(c, 99, fs);
if(rc==NULL) { break; }
if((Data = strstr(rc, "Device"))!= NULL)
printf("%s", Data);
}
fclose ( fs ) ;
return 0;
}
Проблемы, которые я нашел:
exit()
exit()
Data[5]
fgetc()
в fgets()
Я только сделал минимальные правки — это не идеально …
ИМХО, я бы пошел на C ++: там гораздо проще.
Если printf()
это не жесткое / быстрое правило, а требования к входным данным на самом деле так просты, я бы предпочел конечный автомат и постоянную память:
int c, x = 0; // c is character, x is state
while(EOF!=(c=getchar())){ // scanner entry point
if(c == '\n') x=0; // newline resets scanner
else if(x == -1) continue; // -1 is invalid state
else if (x < 7 && c=="Device:"[x])x++; // advance state
else if (x == 7 && isspace(c)) continue; // skip leading/trailing whitespace
else if (x == 7) putchar(c); // successful terminator (exits at \n)
else x = -1; // otherwise move to invalid state
}
Я сделал бы это с двумя циклами: один для получения строки из файла и другой для создания токенов из строки.
что-то вроде:
#define BUFFSIZE 1024
int main()....
char buff[BUFFSIZE];
char delims[] = " ";
char *result = NULL;
int stop = 0;
fp = fopen("yourFile", "r");
while( fgets(buff, BUFFSIZE,fp) != NULL ) /*This returns null when the file is over*/
{
result = strtok( buff, delims ); /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/
while(result != NULL){ /*Strtok returns null when finishes reading the given string*/
if(strcmp(result,"Device")==0){ /*strcmp returns 0 if the strings are equal*/
stop = 1; /*Update the flag*/
break; /*Is now possible to break the loop*/
}
result = strtok(NULL,delims); /*Get the next token*/
}
if(stop == 1) break; /*This uses the inside flag to stop the outer loop*/
}result = strtok(NULL, delims); /*Result, now, has the string you want: 12345 */
...
этот код не очень точный, и я не проверял его, но именно так я и попытался бы это сделать.
Надеюсь это поможет.
Я предлагаю использовать fread для чтения всего файла. Вы можете читать его символ за символом, но имхо (личный вкус здесь) проще получить строку, содержащую все символы, а затем манипулировать ею.
Это прототип функции:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
Возвращает количество прочитанных элементов.
Например:
char buffer[100];
size_t n= fread(buffer, 1,100, fs);
Затем вы можете манипулировать строкой и делить ее на токены.
РЕДАКТИРОВАТЬ
Здесь есть хорошая ссылка с примером того, как разделить строку на токены:
c
а также Data
являются символьными указателями, указателями на (начало списка) символьных значений.
fgetc
прототип int fgetc ( FILE * stream );
это означает, что он возвращает (одно) целочисленное значение (целое число может быть преобразовано в одно значение символа).
Если fgetc
прототип был бы int * fgetc ( FILE * stream );
предупреждение не появилось бы.
@ Дэйв Ван
Мой ответ был слишком большим, чтобы быть комментарием. Так что вот так:
Пожалуйста. Рад помочь.
Если вы сделаете новый цикл, fgets не будет работать, потому что вы уже «вниз» в текстовом файле. Представьте себе что-то вроде указателя на файл, каждый раз, когда вы «получаете его» из указателя файла, вы продвигаете этот указатель. У вас есть функции для перезагрузки файла или перемещения этого указателя вверх, но это неэффективно, вы уже передали нужную информацию, должен быть способ узнать, когда.
Если вы используете мою реализацию, это делается с помощью сравнения строк внутри цикла:
if (strcmp (result, «date») == 0)
Если вы введете это if, вы будете знать, что следующее значение в токене результата со strtok — это фактическая дата.
Поскольку теперь у вас есть два условия для тестирования, вы не можете разорвать внешний цикл до того, как получите оба. Это может быть достигнуто двумя способами:
1-Вместо флага используйте счетчик, который увеличивается каждый раз, когда вы хотите получить информацию. Если этот счетчик имеет столько же информации, сколько вы хотите, вы можете прервать внешний цикл.
2-Не ломайте внешнюю петлю! 🙂
Но в обоих случаях, поскольку есть 2 условия, убедитесь, что вы относитесь к ним внутри if, чтобы вы знали, что имеете дело с правильной информацией.
Надеюсь это поможет. Что-нибудь, просто спросите.