Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Алгоритм поиска строк в текстовом файле  (Прочитано 27731 раз)
0 Пользователей и 1 Гость смотрят эту тему.
0k
Гость
« : 19-04-2008 09:39 » 

Доброго времени суток!
Есть текстовый файл размером ~65 Мб, ~605000 строк. Из этих строк необходимо выделить строки, котрые содержат подстроки "10077" и "Новая запись:" и сохранить их в другой текстовый файл. Написал следующий код:

Код:
#include <stdio.h>
#include <string.h>

int main(void)
{
    FILE* log_file;
    FILE* result_file;
    char current_str[1000];

    if(!(log_file=fopen("log.txt", "r")))
    {
        printf("Open log_file failed.\n");
        return 0;
    }

    result_file=fopen("result.txt", "w");

    fin: while(!(feof(log_file)))
    {
        fgets(current_str, 1000, log_file);

        if (ferror(log_file))
        {
            printf("error");
            return 0;
        }

        if (((strstr(current_str,"10077"))!=NULL)&&((strstr(c urrent_str,"Новая запись:"))!=NULL))
        {
            fputs(current_str, stdout);
            fputs(current_str, result_file);
        }
        else
            goto fin;
    }

    fclose(log_file);
    fclose(result_file);

    return 0;
}

код работает, но обрабатывает файл не до конца: только 750 строк. В чем ошибка?
« Последнее редактирование: 19-04-2008 09:56 от Вад » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #1 : 19-04-2008 09:48 » 

0k, для на чала исправь код так, чтобы там не использовалось GOTO Улыбаюсь
Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 19-04-2008 10:27 » 

Тоже не понял, к чему там goto. 65мегабайтных текстовых файлов у меня нет, поэтому испытал на 1,2 МБ - проходит до конца.
Цитата
Из этих строк необходимо выделить строки, котрые содержат подстроки "10077" и "Новая запись:"
Содержат обе подстроки одновременно?

Ещё смущает return из цикла без закрытия дескрипторов файлов - если будет ошибка, можешь потерять данные, по идее.
« Последнее редактирование: 19-04-2008 10:30 от Вад » Записан
0k
Гость
« Ответ #3 : 20-04-2008 05:25 » 

0k, для на чала исправь код так, чтобы там не использовалось GOTO Улыбаюсь
сорри. конечно, это нафик здесь не надо. сказывается бейсиковское детство) Исправил:
Код:
#include <stdio.h>
#include <string.h>

int main(void)
{
 FILE* log_file;
 FILE* result_file;
 char current_str[500];

 /*if(!(log_file=fopen("log.txt", "r")))
 {
  printf("Open log_file failed.\n");
  return 0;
 }
*/
 
 log_file=fopen("log.txt", "r");
 result_file=fopen("result.txt", "w");
 
 while(!(feof(log_file)))
   {   
    fgets(current_str, 500, log_file);

if (ferror(log_file))
{
    printf("error");
return 0;
}

    if (((strchr(current_str, '+'))==NULL)&&((strchr(current_str, '*'))==NULL))
{
  if (((strstr(current_str,"10077"))!=NULL)&&((strstr(current_str,"Новая запись:"))!=NULL))
        {
         fputs(current_str, stdout);
fputs(current_str, result_file);     
        }  
     }
   }
 
 fclose(log_file);
 fclose(result_file);

 return 0;
}
Вад, нужно выделить строку, в которой содержатся обе эти строки одновременно.
Здесь еще один момент... файл кроме символов, содержит бинарные данные, перед которыми стоят символы "+" или "*". Может из-за этого затыкается?
« Последнее редактирование: 20-04-2008 07:49 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 20-04-2008 05:52 » 

Цитата: Ok
файл кроме символов, содержит бинарные данные, перед которыми стоят символы "+" или "*".
А после них что стоит? Или какова их длина? И считать ли их за одну строчку (несмотря на возможные в них символы перевода строки и нулевые символы)?

Цитата: Ok
f (((strstr(current_str,"10077"))!=NULL)&&((strstr(current_str,"Новая запись:"))!=NULL))
Ещё полезно бы знать алгоритм поиска подстроки в строке, чтобы адаптировать его и искать всё нужное за один проход. Впрочем, это не необходимость, а пожелание.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #5 : 21-04-2008 04:37 » 

Код:
int _tmain(int argc, _TCHAR* argv[])
{
std::ifstream inf("input.txt");
std::ofstream outf("output.txt");

while (!inf.eof())
{
std::string tmp_str;
std::getline(inf, tmp_str);

if ((std::string::npos != tmp_str.find("10077")) && (std::string::npos != tmp_str.find("Новая запись:")))
outf << tmp_str << "\n";
}

return 0;
}
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 21-04-2008 05:16 » 

Цитата: LogRus
std::getline(inf, tmp_str);
Это с бинарными данными может обломиться, если в бинарных данных найдётся \n.

Хотя если искать сами вхождения, а не строки, их содержащие, то не важно.
« Последнее редактирование: 21-04-2008 05:18 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
0k
Гость
« Ответ #7 : 22-04-2008 04:37 » 

Всем спасибо за помощь! Заработало. Изменил метод доступа с текстового на бинарный и еще кой-чего поправил:

Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 FILE* log_file;
 FILE* result_file;
 char current_str[500];
 unsigned long n,i=0;
 unsigned long k=0;

 log_file=fopen("e:\\log_080421.txt", "rb");

 if (log_file==NULL)
  {
    printf("Open log_file failed.\n");
    return;
  }

 result_file=fopen("e:\\77777_210408.txt","w");

 ProgressBar1->Max=500;

 while(!(feof(log_file)))
   {
     Application->ProcessMessages();
     if(f==1)return;
     n=fread(&current_str[i],1,1,log_file);
     i++;
     ProgressBar1->Position++;
     if((current_str[i-1]==0x0A)&&(current_str[i-2]==0x0D))
       {
        if(((strstr(current_str,"10077"))!=NULL)&&((strstr(current_str,"Новая запись:"))!=NULL))
          {
            fputs(current_str, result_file);
          }
        for (k=0;k<500;k++)current_str[k]=0x00;
        i=0;
        ProgressBar1->Position=0;
       }
    }

 fclose(log_file);
 fclose(result_file);

 return;
}
« Последнее редактирование: 22-04-2008 05:07 от Вад » Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 22-04-2008 05:16 » 

Код:
if(f==1)return;
я бы лучше сделал break вместо return - так хотя бы точно закроются дескрипторы файлов, да и одна точка выхода в таких случаях, имхо, лучше, чем две, при том, что во втором случае одна - в теле цикла Улыбаюсь

Побайтовое чтение сделал? Имхо, не самый лучший вариант. Тогда уж реализация через iostreem выглядела бы логичнее, наверное.
Ты говорил что-то о бинарных данных - ты их сейчас просто пропускаешь через поиск наравне с остальными данными, выходит.

Ну и заполнение строки нулями - насколько оно вообще имеет смысл? Улыбаюсь Может, стоит просто делать
Код:
if((current_str[i-1]==0x0A)&&(current_str[i-2]==0x0D))
{
    current_str[i]=0;
    // ...
}
?
Записан
0k
Гость
« Ответ #9 : 23-04-2008 11:44 » 


Ну и заполнение строки нулями - насколько оно вообще имеет смысл? Улыбаюсь Может, стоит просто делать
Код:
if((current_str[i-1]==0x0A)&&(current_str[i-2]==0x0D))
{
    current_str[i]=0;
    // ...
}
?

мне нужно очистить массив. Сделал так:
Код:
for (k=0;k<=i;k++)current_str[k]=0x00;
заработало быстрее
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #10 : 23-04-2008 12:16 » 

0k, просто я не увидел смысла в очистке строки - зануление у тебя используется только для того, чтобы на следующей итерации строка после посимвольного чтения была NULL-terminated, чтобы можно было корректно с ней дальше работать. Вот и предложил оптимизацию Улыбаюсь
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


WWW
« Ответ #11 : 23-04-2008 13:54 » 

>>заработало быстрее

а вот так ещё быстрее будет Улыбаюсь
memset(current_str,0,i);

а всё таки воот так - ещёёёё быстрее Улыбаюсь
current_str[0]=0;
Записан

0k
Гость
« Ответ #12 : 26-04-2008 10:01 » 

Всем спасибо.
Оффтопик, но все же... Как в C Builder передавать пути к файлам из OpenDialog и SaveDialog (AnsiString) в fopen (char*) и задавать строки для поиска в Edit? Т.е. нужно преобразовать AnsiString в char.
Записан
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #13 : 26-04-2008 10:14 » 

ְAnsiString по идее говоря хранит строку как массив чаров. Можно попробовать (char *)string или &string[0], а лучше почитать хелп.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
marat_
Шеф-повар
Опытный

ru
Offline Offline

« Ответ #14 : 26-04-2008 10:37 » 

в классе ansistring есть метод c_str(). возвращает char*
Записан
0k
Гость
« Ответ #15 : 29-04-2008 04:34 » 

в классе ansistring есть метод c_str(). возвращает char*
Спасибо, все получилось
Записан
marat_
Шеф-повар
Опытный

ru
Offline Offline

« Ответ #16 : 29-04-2008 11:09 » 

не за что, обращайся Улыбаюсь
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines