Помощь - Поиск - Пользователи - Календарь
Полная версия: Как найти максимальное число в тексте?
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Delphi
KljaGGsa
Если есть текстовый файл Т.txt , в тексте которого содержится несколько трехзначных чисел, как должна выглядеть процедура, с помощью которой можно было бы найти максимальное число и присвоить его целочисленной переменной i ?
volvo
Что кроме чисел есть в файле, и чем отделяются слова/числа друг от друга?
KljaGGsa
Вот образец содержимого файла:

001

фрагмент текста 1

002

фрагмент текста 2

003

фрагмент текста 3

004

фрагмент текста 4

. . . . . . . . . . . .


Трехзначные числа назовем метками и нужно элементарно определить количество меток и соответственно фрагментов
текста. Длина фрагмента может превышать 255 символов
volvo
Цитата
и нужно элементарно определить количество меток и соответственно фрагментов текста.
Общее количество строк в файле...
var sL: TStringList;
begin
sL := TStringList.Create;
try
sL.LoadFromFile('t.txt');
ShowMessage(IntToStr(sl.Count)); // <--- ... вычисляется вот так ...
finally
sL.Free;
end;
end;
..., а если его поделить на 2 - получишь количество фрагментов текста. Естественно, если внутри фрагмента может быть перевод строки, то придется чуть-чуть изменить алгоритм:
  sL := TStringList.Create; // Создаем СтрингЛист
try
sL.LoadFromFile('t.txt'); // читаем текст в Стринглист
// при этом всё, что до первого перевода строки будет записано в первую строку СтрингЛиста,
// после первого, но до второго - во вторую строку СтрингЛиста и т.д.
// Т.е., текст разбивается по строкам...

cnt := 0; // Обнуляем счетчик
for i := 0 to sL.Count - 1 do // Проходим по всем строкам СтрингЛиста и проверяем их содержимое
// если попытка перевести содержимое строки в число (TryStrToInt делает именно это)
// удачна (функция TryStrToInt вернула True), значит это - метка, и счетчик меток увеличиваем
// В случае неудачной попытки перевода в число TryStrToInt вернет False, а раз нельзя перевести
// что-то в число, то это "что-то" не может быть меткой, это фрагмент текста
if TryStrToInt(sL.Strings[i], value) Then Inc(cnt);

ShowMessage(IntToStr(cnt)); // Показываем, чего насчитали
finally
sL.Free; // Удаляем СтрингЛист полностью, он нам не нужен больше
end;
KljaGGsa
Вот на эту строчку:

if TryStrToInt(sL.Strings[i], value) Then Inc(cnt);

компилятор выводит сообщение:

[Error] Unit1.pas(60): Undeclared identifier: 'value'
volvo
Ну, так переменную Value типа Integer надо описать... И cnt тоже.
KljaGGsa
Владимир, а можно Вас попросить добавить комментарии в код, чтобы было понятнее как оно работает


sL := TStringList.Create; //совсем непонятное действие)))
try // что это за оператор???
sL.LoadFromFile('t.txt'); //загружаем в переменную sL весь текст из файла T.txt
cnt := 0; // целочисленной переменной cnt даем значение 0
for i := 0 to sL.Count - 1 do // делаем какой-то цикл
if TryStrToInt(sL.Strings[i], value) Then Inc(cnt); // это чо?
ShowMessage(IntToStr(cnt)); // ну здесь понятно, выводим значение переменной cnt во внешнее окошечко
finally
sL.Free; // Удаляем текст из текстовой переменной sL?
end;




volvo
Комментарии добавлены...
KljaGGsa
Так хотелось бы с вашей помощью эти комментарии причесать, а то половина из них выражает непонимание)))

А еще вопрос - в процедуре скажем Button1Click могут быть несколько последовательных фрагментов кода, заключенных в слова begin и end?
volvo
KljaGGsa, я имел в виду, что я в свой код, выше (в сообщении №4), добавил комментарии...

Цитата
в процедуре скажем Button1Click могут быть несколько последовательных фрагментов кода, заключенных в слова begin и end
Могут, только если они находятся внутри блока begin/end самой процедуры.
procedure TForm1.Button1Click;
begin
begin
// первый фрагмент
end;

begin
// второй фрагмент
end;
end;
KljaGGsa
Есть целочисленная переменная r, значение которой произвольно соответствует одному из промежуточных значений переменной cnt, и переменная sL2 типа TStringList.
Как теперь присвоить переменной sL2 содержимое фрагмента текста файла Т.txt с условным номером r?
volvo
Смотри:
procedure TForm1.Button2Click(Sender: TObject);
var
sL, sL2: TStringList;
i, value, p: integer;
begin
sL := TStringList.Create;
try
sL.LoadFromFile('t.txt'); // Получаем текст, разбитый на строки

sL2 := TStringList.Create; // создаем доп. СтрингЛист
try
p := 5; // Будем искать в файле фрагмент № 5 !!!

i := 0; // Начиная с нулевой строки sL проходим ...
while p > 0 do begin
// Пока не дойдем до числа, являющегося меткой
// нужного нам фрагмента, проверяем строки ...
if TryStrToInt(sL.Strings[i], value) then begin
dec(p); // Очередная метка? Уменьшаем P ...
end;
inc(i); // следующая строка СтрингЛиста
end;

// Все, раз мы здесь - то нашли уже метку нужного фрагмента,
// теперь надо считать во второй СтрингЛист все строки ДО
// очередной, следующей метки (или до конца sL, смотря что
// случится раньше).
while (i < sL.Count) and (not TryStrToInt(sL.Strings[i], value)) do
begin
sL2.Add(sL.Strings[i]); inc(i); // Не метка? Добавляем в sL2
end;

// Ну, этого можно было и не делать, я просто отобразил
// полученный фрагмент в Memo
Memo1.Lines.Assign(sL2);
finally
sL2.Free; // Все, больше sL2 не нужен ...
end;

finally
sL.Free; // sL тоже ...
end;
end;
Переменная P должна содержать номер фрагмента, который ищется. Единственное, о чем ты должна позаботиться - это о том, что такой фрагмент действительно есть, P не должно быть больше числа фрагментов в файле. Мой код не проверяет этот случай. Хочешь - дописывай проверку сама, я этого делать не буду.
KljaGGsa
Ну да, мы изначально условились, что r входит в диапазон значений cnt, то есть такой проблемы возникнуть не должно... Пасибки! smile.gif
youngDelphyGirl
Цитата(volvo @ 6.07.2009 17:41) *

p := 5; // Будем искать в файле фрагмент № 5 !!!




А если мы даже приблизительно не знаем, сколько фрагментов содержится в тексте? Или это количество фрагментов постоянно меняется? Как тогда быть??
volvo
Цитата(youngDelphyGirl @ 5.08.2009 3:17) *
А если мы даже приблизительно не знаем, сколько фрагментов содержится в тексте? Или это количество фрагментов постоянно меняется? Как тогда быть??
А нам и не надо знать, сколько фрагментов в тексте. Нам надо знать, какой фрагмент мы ищем (по крайней мере в той задаче, которая была поставлена изначально). Если у тебя другая задача - задавай свой вопрос отдельно, формулируй ее, посмотрим, что можно сделать.
youngDelphyGirl
Цитата(volvo @ 5.08.2009 8:15) *

А нам и не надо знать, сколько фрагментов в тексте. Нам надо знать, какой фрагмент мы ищем (по крайней мере в той задаче, которая была поставлена изначально). Если у тебя другая задача - задавай свой вопрос отдельно, формулируй ее, посмотрим, что можно сделать.



А "задать вопрос отдельно" - можно здесь?

Вопрос похожий - разместить в файле фрагменты различного объема, в некоторых случаях более 255 символов. Сделать так, чтобы их можно было пересчитать и выбрать какой-либо один функцией random и вывести его в Memo1. Также предусмотреть возможность добавить или удалить фрагмент.
Так как предусматривается возможность удаления фрагментов, по видимому присваивать им порядковые номера было бы неправильно, иначе пришлось бы заново нумеровать все фрагменты после одного удаленного. По видимому, нужно разделить фрагменты определенным символом и после переноса содержимого файла в переменную типа TStrings или TStringList подсчитать общее число этих символов, а потом оперировать этим числом? А при добавлении из Memo2 очередного фрагмента, добавлять и этот символ, чтобы добавленный фрагмент вписался в общую картину smile.gif И наверное Memo2 следует разместить в Form2, которую делать видимой только для случая добавления фрагмента?
Пока что собственного опыта для корректного написания кода несколько не хватает, поэтому позволю себе нескромно обратиться за помощью к специалистам)))) smile.gif
volvo
В принципе, не вижу проблем, чтоб хранить в файле строки длиной больше 255 символов. Длина строки AnsiString (или WideString) может достигать 2Гб. Тогда StringList.Count выдаст число строк, и не надо ничего искать.

Единственное, на что надо обратить внимание при чтении из этого файла в StringList: разбивается содержимое файла построчно и по тому символу, который задан в DelimiterChar, то есть, перед сохранением Memo->File надо все сочетания #13#10 заменить на какой-нибудь особый символ или последовательность (StringReplace подходит для этого как нельзя лучше), а потом, когда нужный фрагмент в StringList-е уже найден, заменить эту последовательность назад на #13#10.

Добавлено через 2 мин.
P.S. Викторину какую-то пишешь что-ли? Может, выгоднее засунуть вопросы в БД (скажем, MSAccess)? Чем больше будет вопросов - тем выгоднее будет решение с Базой Данных. Мало ли, вдруг захочется еще и вопросы с изображениями включить... smile.gif
youngDelphyGirl
Цитата(volvo @ 6.08.2009 11:14) *


Единственное, на что надо обратить внимание при чтении из этого файла в StringList: разбивается содержимое файла построчно и по тому символу, который задан в DelimiterChar, то есть, перед сохранением Memo->File надо все сочетания #13#10 заменить на какой-нибудь особый символ или последовательность (StringReplace подходит для этого как нельзя лучше), а потом, когда нужный фрагмент в StringList-е уже найден, заменить эту последовательность назад на #13#10.


Как превратить эти светлые соображения в код, пока что представляю очень неясно . . . unsure.gif


Цитата(volvo @ 6.08.2009 11:14) *

P.S. Викторину какую-то пишешь что-ли? Может, выгоднее засунуть вопросы в БД (скажем, MSAccess)? Чем больше будет вопросов - тем выгоднее будет решение с Базой Данных. Мало ли, вдруг захочется еще и вопросы с изображениями включить... smile.gif


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



volvo
Цитата
Как превратить эти светлые соображения в код
Очень просто...

На форме - Мемо, и две кнопки, одна для сохранения в файл текущего содержимого Memo, а вторая - для занесения в Memo случайного фрагмента из файла. Плюс к этому - TSaveDialog + TOpenDialog для задания имен файлов:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Memo1: TMemo;
Save: TButton;
Random: TButton;
SaveDialog1: TSaveDialog;
OpenDialog1: TOpenDialog;
procedure SaveClick(Sender: TObject);
procedure RandomClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
Randomize;
end;

procedure TForm1.RandomClick(Sender: TObject);
var
SL: TStringList;
num: Integer;
begin
SL := TStringList.Create;
try
if OpenDialog1.Execute() then begin
SL.LoadFromFile(OpenDialog1.FileName);
num := System.Random(SL.Count);
Memo1.Text := StringReplace(SL.Strings[num], '<br>', #13#10, [rfReplaceAll]);
end;
finally
SL.Free
end;
end;

procedure TForm1.SaveClick(Sender: TObject);
var
f: TextFile;
begin
if SaveDialog1.FileName = '' then begin
if not SaveDialog1.Execute() then Exit;
end;
AssignFile(f, SaveDialog1.FileName);
try
Append(f);
except
Rewrite(f);
end;
WriteLn(f, StringReplace(Memo1.Text, #13#10, '<br>', [rfReplaceAll]));
CloseFile(f);
end;

end.
Если что непонятно - спрашивай...
youngDelphyGirl
Спасибо, сейчас начну писать построчные комментарии, чтобы детально разобраться ))
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.