Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Считывание текстового файла сложной структуры, Работа с файлами 
V
    Опции темы
Pellegrino
Дата 28.1.2010, 23:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



Уважаемые, столкнулся с такой непростой задачкой, как работа с текстовым файлом сложной структуры. Нужно считать с него коды станций, номера платежей, суммы и коды статей. И дату. Желательно в табличку запихнуть для удобства работы. Единственный вариант, который приходит в голову, это построчное считывание и анализ. Подскажите какими методами такое можно провернуть? 

Это сообщение отредактировал(а) Pellegrino - 28.1.2010, 23:08

Присоединённый файл ( Кол-во скачиваний: 42 )
Присоединённый файл  razsb.txt 3,45 Kb
PM MAIL WWW   Вверх
Данкинг
Дата 28.1.2010, 23:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Yersinia pestis
****


Профиль
Группа: Завсегдатай
Сообщений: 8302
Регистрация: 7.11.2006
Где: მოსკოვი

Репутация: 11
Всего: 130



Цитата(Pellegrino @  28.1.2010,  23:06 Найти цитируемый пост)
Подскажите какими методами такое можно провернуть? 

Так грузи в Memo, а дальше парси всякими строковыми функцями вроде "copy".


--------------------
There's nothing left but silent epitaphs.
PM MAIL WWW   Вверх
chip_and_dayl
Дата 28.1.2010, 23:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 603
Регистрация: 22.4.2007
Где: Украина, Киев

Репутация: 1
Всего: 9



Pellegrino
Лучше всего структура файла сменить

Цитата(Pellegrino @  28.1.2010,  23:06 Найти цитируемый пост)
Единственный вариант, который приходит в голову, это построчное считывание и анализ

Я даже бы сказал - посимвольный 


--------------------
Фсё будет хорошо!!!
PM MAIL Skype   Вверх
Pellegrino
Дата 29.1.2010, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



Файл менять не могу и структуру тоже. Данные нужны для БД. Конкретно привязать не могу именно к copy, так как длина названий везде разная и это только 1\5 файла.  А как сделать чтобы записывал только суммы из строк со словами "по станции"?
PM MAIL WWW   Вверх
chip_and_dayl
Дата 29.1.2010, 20:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 603
Регистрация: 22.4.2007
Где: Украина, Киев

Репутация: 1
Всего: 9



Значить алгоритм, приблизительно такой.
1.  Загружаем/открываем текстовой файл
2. Ищем строку "по станции" (ф-ций поиска хватает)
3. Запоминаем номер строки и запускаем поиск уже по строке, в которой нашли слово "по станции"
4. Заносим сумму в базу
5. Ищем  следующую строку, где находиться слово "по станции"

Добавлено @ 20:40
Тут вопрос может возникнуть только в пункте 3. Как искать!?! Или тупым перебором, то  есть каждую строку анализировать на символ  "|" и когда, мы найдем в строке второй символ "|", то мы знаем, что за вторым символом уже идет желаемая сумма, то  мы откидываем пробелы и заносим сумму в базу.
Второй вариант, найти ф-цию поиска, которая ищет по шаблону

Это сообщение отредактировал(а) chip_and_dayl - 29.1.2010, 20:41


--------------------
Фсё будет хорошо!!!
PM MAIL Skype   Вверх
Pellegrino
Дата 29.1.2010, 21:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



Вот у меня была идея искать на подобе какойнить маски.
PM MAIL WWW   Вверх
Демо
Дата 29.1.2010, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1278
Регистрация: 3.11.2005

Репутация: 7
Всего: 50



Так вроде нет никаких проблем разобрать файл.

Конечный автомат - стандартный алгоритм.


--------------------
    
PM MAIL ICQ Skype   Вверх
kami
Дата 30.1.2010, 01:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Я чего-то возможно не понимаю, но не вижу никакой проблемы разобрать этот файл.
Длина строки - фиксированная.
Длина каждой ячейки - тоже.
Функции copy вместе с trim хватит с головой и даже больше...
Если я правильно понял структуру файла, то:

Код

type
  TPayRecord = record
    Name: string;
    Code: integer;
    Caption: string;
    Summ: Double;
    StNum: integer;
  end;

  TPayRecordArray = array of TPayRecord;

  TStation = record
    StationCode: integer;
    StationSumm: Double;
    Pays: TPayRecordArray;
  end;

  TStations = array of TStation;

  TBufType = (btDivider, btPay, btStation);

function DescribeBufType(const Buf: string): TBufType;
begin
  Result := btDivider;
  // длина строки в образце фиксированная.
  if Length(Buf) <> 126 then
    exit;
  if Buf[1] = ':' then
    Exit;
  if Buf[6] = '|' then
    Result := btPay
  else
    if Pos('ПО СТАНЦИИ', Buf)<>0 then
      Result := btStation; // так как в таблице есть еще строка "ОТДЕЛЕНИЕ -  1",
      // назначение которой не оговаривалось, не помешает дополнительная проверка
      // на принадлежность строки - к итоговой по станции.
end;

procedure ParseStation(Buf: string; var Station: TStation);
begin
  Station.StationCode := StrToInt(Trim(Copy(Buf, 15, 89)));
  Station.StationSumm := StrToFloat(Copy(Buf, 106, 13));
end;

procedure ParsePay(Buf: string; var Pay: TPayRecord);
begin
  Pay.Name := Trim(Copy(Buf, 7, 10));
  Pay.Code := StrToInt(Trim(Copy(buf, 18, 7)));
  Pay.Caption := Trim(Copy(Buf, 26, 79));
  Pay.Summ := StrToFloat(Trim(Copy(Buf, 106, 13)));
  Pay.StNum := StrToInt(Trim(Copy(Buf, 120, 6)));
end;

procedure ParseFile(FileName: string; var Stations: TStations);
var
  f: TextFile;
  buf: string;
  iStations, iPays: Integer;
  i: integer;
begin
  DecimalSeparator:='.';

  iStations := 0;
  iPays := 0;
  SetLength(Stations, 1);
  SetLength(Stations[0].Pays, 1);

  AssignFile(f, FileName);
  Reset(f);
  // пропускаем начальные строки - заголовок таблицы и все такое.
  // Дату предлагаю "забрать" самому.
  for i := 1 to 14 do
    Readln(f);

  while not Eof(f) do
    begin
      Readln(f, buf);
      case DescribeBufType(buf) of
        btDivider: ;
        btPay:
          begin
            ParsePay(buf, Stations[iStations].Pays[iPays]);
            if Stations[iStations].Pays[iPays].Name = '' then
              if iPays > 0 then
                Stations[iStations].Pays[iPays].Name := Stations[iStations].Pays[iPays - 1].Name;
            Inc(iPays);
            SetLength(Stations[iStations].Pays, iPays + 1);
          end;
        btStation:
          begin
            ParseStation(buf, Stations[iStations]);
            Inc(iStations);
            SetLength(Stations, iStations + 1);
            SetLength(Stations[iStations].Pays, 1);
            iPays:=0;
          end;
      end;
    end;
end;

procedure ClearStations(var Stations: TStations);
var
  i, j: integer;
begin
  // из-за несовершенства алгоритма
  // в каждом из массивов последний элемент будет
  // пустым. Убираем лишнее.
  for i := 0 to Length(Stations) - 1 do
    begin
      j := Length(Stations[i].Pays);
      if j <> 0 then
        if Stations[i].Pays[j-1].Name = '' then
          SetLength(Stations[i].Pays, j - 1);
    end;
  i:=Length(Stations)-1;
  if Stations[i].StationCode=0 then
    SetLength(Stations, i);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Stations:TStations;
begin
  if OpenDialog1.Execute then
    begin
      ParseFile(OpenDialog1.FileName, Stations);
      ClearStations(Stations);
    end;
  // теперь в Stations содержатся коды станций и суммы платежей
  // а в Stations[i].Pays - платежи.
  // можно делать с ними, что угодно...
end;


Это сообщение отредактировал(а) kami - 30.1.2010, 01:33
PM MAIL WWW   Вверх
Pellegrino
Дата 1.2.2010, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



Круто, спасибо. А как добавить еще коды платежей и суммы по ним? Еще вопрос, что за регулярные выражения, они могут тут помочь? А в данные из типа рекорд можно в стингГрид укладывать? smile 

Это сообщение отредактировал(а) Pellegrino - 1.2.2010, 14:08
PM MAIL WWW   Вверх
profesiachuvak
Дата 1.2.2010, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 283
Регистрация: 7.11.2009
Где: Беларусь, Минск

Репутация: 1
Всего: 4



Цитата(Pellegrino @  1.2.2010,  14:00 Найти цитируемый пост)
А в данные из типа рекорд можно в стингГрид укладывать? smile 


Обращаться к fields (полям) записи и выводить их в StringGrid.


--------------------
Закон Мерфи :если есть вероятность того, что какая-нибудь неприятность может случиться, то она обязательно произойдет.
PM MAIL   Вверх
kami
Дата 1.2.2010, 18:49 (ссылка) |  (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(Pellegrino @  1.2.2010,  14:00 Найти цитируемый пост)
. А как добавить еще коды платежей и суммы по ним?

Не понял вопроса, или Вы не читали мой ответ.
Stations[i].Pays[j].Code и Summ - это разве не то, что нужно? Строка платежа разбирается полностью по всем колонкам за исключением порядкового номера.

Цитата(Pellegrino @  1.2.2010,  14:00 Найти цитируемый пост)
 Еще вопрос, что за регулярные выражения, они могут тут помочь?

Не ко мне.

Цитата(Pellegrino @  1.2.2010,  14:00 Найти цитируемый пост)
А в данные из типа рекорд можно в стингГрид укладывать?

Более чем можно, и к этому нет никаких препятствий. Только давайте так - решать за Вас Вашу задачу здесь, имхо, не будут. За этим - в "Центр Помощи". С учетом того, что я и так сказал больше, чем нужно было, предлагаю следующее - Вы попробуете сами перенести данные из записей в StringGrid. Если что-то не получится - с конкретным вопросом и своим "работающим не так, как нужно" кодом - пожалуйста сюда.
PM MAIL WWW   Вверх
Pellegrino
Дата 1.2.2010, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



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

//чтение из файла
    while not EOF(f) do
    begin
        readln(f,buf);    // прочитать строку из файла
        Memo1.Lines.Add(buf); // добавить строку в поле Memo1
       if buf[27]='З' then
        Form4.Edit2.Text:=copy(buf,30,42);
        end;
      CloseFile(f); // закрыть файл
      begin
         Form4.ComboBox1.Text:=mounth;
         Form4.Edit3.Text:=god;
         data1:=mounth + ' ' + god;
         Form4.Edit3.text:=data2;

      end;
         end;



PM MAIL WWW   Вверх
kami
Дата 1.2.2010, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Код с моими комментариями:
Код

while not EOF(f) do
  begin
    readln(f,buf);    // это понятно.
    Memo1.Lines.Add(buf); // А это зачем? В изначальном вопросе не сказано, что всё подряд из файла нужно загружать в Memo
    if buf[27]='З' then // не проще ли "пролистать" до шестой строки и забрать оттуда нужное?
      Form4.Edit2.Text:=copy(buf,30,42); // строка с этой датой имеет переменную длину ровно по дате,
                                         // я бы забирал так: copy(buf, 30, Length(buf)), т.е. с 30 символа и до конца.
                                                             
  end;  // почему, найдя нужное, мы все равно продолжаем проходить остаток файла и заносить всё из него в memo?
        // а если файл будет гигантского размера?
CloseFile(f); // закрыть файл
  begin
    Form4.ComboBox1.Text:=mounth; // из кода непонятно, откуда взялись эти переменные - month, god (имхо, лучше year :) )
    Form4.Edit3.Text:=god;
    data1:=mounth + ' ' + god;
    Form4.Edit3.text:=data2;
  end;
end;


Замечание не по теме - для удобства чтения другими вашего кода, неплохо было бы оформлять его, придерживаясь правил, принятых у создателей VCL. Да и обзывать компоненты лучше осмысленными именами, чтобы не пришлось мучительно искать - "а что же отображает Edit94 на Form31".

Это сообщение отредактировал(а) kami - 1.2.2010, 23:38
PM MAIL WWW   Вверх
Pellegrino
Дата 2.2.2010, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 32
Регистрация: 13.3.2007
Где: Russian Federatio n

Репутация: нет
Всего: нет



По моей задумке пользователь вводит год в эдите3 и выбирает месяц из комбоБокса, а после я захватываю дату и сравниваю её с введенным, если нет совпадения, то вывожу сообщение об ошибке ввода и блокирую кнопку записи в БД. А как до 6 строки пролистать -  for i:=0 do 5 then таким образом? Еще проблема возникла в том, что версия проги выбрасывающая отчет сменилась, и изменился отчетный файлик. В нем три вида отчетов, мне нужны станции с кодами платежей и цифрами по ним по ФО-7л и ФО-7н, Фо-7М не нужно. Возникла идея разбить на два текстовика с нужным содержим по Фо-7л и Н, а как можно определять начало и концовки их? 

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  razsb.txt 47,17 Kb
PM MAIL WWW   Вверх
kami
Дата 2.2.2010, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(kami @  1.2.2010,  18:49 Найти цитируемый пост)
решать за Вас Вашу задачу здесь, имхо, не будут. За этим - в "Центр Помощи". ... Если что-то не получится - с конкретным вопросом и своим "работающим не так, как нужно" кодом - пожалуйста сюда.



Это сообщение отредактировал(а) kami - 2.2.2010, 22:36
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.0591 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.