Построчный парсинг

Привет. Сегодня хочу рассмотреть построчную работу с файлом. Использовать будем стандартный паскалевский ввод/вывод: writeln и readln.
Например, перед нами задача: убрать от одного до десяти первых символов в каждой строке. Кстати, передо мной эта задача вчера реально встала, и я написал программу за 5 минут. Теперь и мы с тобой рассмотрим процесс написания.

Итак, сегодня будем писать со всеми прелестями delphi, читай с формой. Соорудим форму, поставим Edit1 и Edit2. Поставим OpenDialog1 и SaveDialog1, да и две кнопки для выбора файла в придачу.
Как это всё связать, думаю тебе известно. Но на всякий случай:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Edit1.Text:=OpenDialog1.FileName;
end;

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  if SaveDialog1.Execute then
    Edit2.Text:=SaveDialog1.FileName;
end;

Переназывать компоненты не станем.

Теперь нам нужно сделать выбор количества — от 1 до 10 символов (на выбор). Для этого я решил поставить TrackBar и Label так, что при изменении значения TrackBar менялось значение Label (от 1 до 10).

Вот так выглядит моя форма:
Form1

Теперь непосредственно парсинг:

procedure TForm1.SpeedButton3Click(Sender: TObject);
var
  f, o: TextFile;
  s: string;
  c: integer;
begin
  c:=TrackBar1.Position;
  if not FileExists(Edit1.Text) then begin
    ShowMessage('file not found');
    Exit;
  end;
  AssignFile(f, Edit1.Text);
  AssignFile(o, Edit1.Text);
  Reset(f); Rewrite(o);
  repeat
    Readln(f, s);
    Delete(s, 1, c);
    Writeln(o, s);
  until Eof(f);
  CloseFile(f); CloseFile(o);
  ShowMessage('ready!');
end;

Как видишь, мы объявили две переменные типа TextFile, строку, которую используем как буфер, и переменную c, в которую записываем количество символов, указанное в TrackBar1.
Теперь теоретическая часть.

Работа с текстовыми файлами

Чтобы связать переменную типа TextFile (или просто text) с конкретным файлом, мы используем процедуру AssignFile (аналог в паскале — assign). Первый параметр — переменная типа TextFile (частный случай file), вторая — адрес файла.
Теперь мы хотим определиться, что же мы собираемся делать с файлом: читать из него, или писать в него? Если читать, надо использовать процедуру Reset с единственным параметром — нашей переменной типа TextFile.
А если мы планируем писать в файл, нам нужна похожая процедура Rewrite. Но учти, что она стирает файл полностью, тем самым мы будем писать с чистого листа. Если файла нет, то она его создаст. Есть также процедура Append, которая открывает на запись, но не стирает, то есть мы можем дописывать в конец файла.
Также следует сказать про функцию Eof, которой мы также передаём TextFile. Она возвращает True только тогда, когда мы своим чтением достигли конца файла. Тем самым для построчного парсинга идеально подходит цикл repeat until.
Построчный ввод и вывод: нет ничего проще! ReadLn — читаем строчку, WriteLn — пишем. Естественно, для соответственно открытых файлов.
Процедура CloseFile закрывает файл, открытый нами с помощью Reset, Rewrite или Append. Однако наша переменная всё еще связано с адресом файла, и мы можем заново открыть на ввод/вывод без использования такого же AssignFile.

Процедура Delete

Процедура Delete удаляет из строки её часть. Синтаксис:

procedure Delete(var S: string; Index, Count: integer);

Передаём процедуре строку, место, с которого начинать удаление (Index), и количество символов для удаления.

Ну вот и всё на сегодня, скачать проект можешь по ссылке.

И, конечно, постовой. Если ты вдруг захотел прочитать про деньги, SEO и раскрутку, то заходи на блог iZombie.ru.

25 ответов к «Построчный парсинг»

  1. Файлики — это классная штука, частенько с ними работаю. Только я, например, цикл repeat редко использую, чаще всего пишу так:

    While (not EOF(FileName)) do
     begin
      //Тело цикла
     end;
    

    Мне кажется, что так проще. :-)

    1. Я изначально преимущественно использовал repeat .. until, привык к нему. Мне в нём привлекает то, что я until ни с каким end не перепутаешь, и всегда видно, где кончается тело цикла

      1. В цикле while есть один плюс в данном случае — если файло пустое, то тело цикла не выполнится ни разу, а с репитом — 1 раз пройдет точно :)

  2. В своё время, разбираясь с текстовыми файлами я выяснил, что Writeln может выводить не только в файл, но и куда душа пожелает. В Memo, в интернет (на какой-нибудь блог) или на принтер. Вывод на принтер — стандартный модуль Printers. Мой модуль для вывода в Memo лежит в кладовке:
    http://kladovka.net.ru/index.cgi?pid=viewprofile&rid=900

      1. Со времён Pascal первой версии в Delphi перекочевали две переменные Input и Output.
        Когда мы пишем
        Writeln(X);, т.е. не указываем файл явно, то компилятор понимает эту строку так: Writeln(Output, X);
        Output — текстовый файл связный со стандартным выводом.
        Это можно использовать для следующего хака:
        Заменив AssignFile(o, Edit1.Text); на AssignFile(Output, Edit1.Text); можно отказаться от переменой O — указывать файл во Writeln уже не нужно.

        Для консольных программ без хака стандартный вывод можно перенаправить в файл с помощью средств ОС.
        Если в консольной программе program.exe написано Writeln(X);, то результат можно отправить в файл logfile.txt так:
        program.exe >logfile.txt
        Зато, если в программе написано AssignFile(o, 'con');, то Writeln(O, X) будет выводить сообщения только на экран игнорируя перенаправление стандартного вывода, т.е. передать сообщения от такой консольной программы в файл или другой программе станет невозможно.
        Writeln — это очень мощный и загадочный инструмент, который достоин более пристального взгляда, чем то, что пишут в книгах.
        Попробуйте догадаться, что выведут на экран следующие команды для разных X:=10.25; X:=’Aaa’; X:=10;
        Writeln(X:10);
        Writeln(X:10:2);
        Writeln(X:2:10);

        1. Последние две команды выдают ошибку для целочисленного и строкового типа (delphi 7). Последняя команда интересная, я так понимаю, что если место, отведённое, под вывод ( :2 ), меньше, чем количество знаков после запятой, оно просто игнорируется, так?

          Использование переменной Output очень удобно, по аналогии попробовал с Input — теперь в обычных приложениях буду именно так файлы читать :)

  3. >> ShowMessage(‘ready!’);
    Лучше написать «Done! «, ибо «ready» — это больше готовность к чему-либо, но никак не завершение (конечно на работоспособности это никак не отражается:))
    П.С. заметил небольшой баг в шаблоне: http://s003.radikal.ru/i203/1001/22/88061f0b7598.png
    браузер Google Chrome, возможно из-за того что надпись «pub» слишком короткая.

  4. Вместо ReadLn и тд лучше курить в сторону Windows API. Оно и работает быстрее и полезнее для программиста — можно применить не только в дельфи.

  5. Автор, в строке 13 и в листинге исходного кода программы и в архиве ошибка.
    в тексте должно быть Edit2, а не Edit1

    фрагмент как должно быть:

    AssignFile(f, Edit1.Text);
    AssignFile(o, Edit2.Text);
    Reset(f); Rewrite(o);

    сейчас:

    AssignFile(f, Edit1.Text);
    AssignFile(o, Edit1.Text);
    Reset(f); Rewrite(o);

  6. Эх… не так давно на подобный код у меня ушло почти пол дня :) Хотя лет 5-7 назад на дельфике даже что то мелкое на заказ писал :) Склероз вообщем

  7. Для консольных программ без хака стандартный вывод можно перенаправить в файл с помощью средств ОС

  8. Простите за вопрос не в тему…
    а сколько будет стоить написать парсер (либо спарсить базу)???
    К примеру база резюме и вакансий.
    что бы потом это все добро можно было прямо в базу данных залить. =)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *