Помощь - Поиск - Пользователи - Календарь
Полная версия: Анализ log-файла...
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Роман
Собственно вот задание: Написать программу по разбивке и анализу содержимого файла отчета работы ПО (log-файла).
Необходимо проанализаровать и подсчитать запросы, а также вывести их в алфавитном порядке с подсчетом колическтва повторений.

Программа должна выдавать отчет о своей работе в виде:

Дата Запросы
25.04.2002 - 12
26.04.2002 - 10
27.04.2002 - 5
...

Всего было сделано (запросов) - 1679

Сортировка запросов:

Бухгалтерский учет - 25
Бухгалтерский журнал - 30
Экономика Томска - 6
Экономика Якутии - 1
...

Пример файла отчета работы программы wslog.txt
Сортировку запросов необходимо проводить по CGI-переменным
S21STR=
S21ALL=
Проблема в том что у меня во второй части программы (подсчет и сортировка самих текстовых запросов) переполняется массив... а вот как сделать без массива не пойму...


program Laba_2;
uses crt;
var
s2:string;
f,f1:text;
g:char;
a,x,i,j,q,p:integer;
zap,m:string;
n:array [1..1000] of byte;
zn:array [1..1000]of string[40];
s,s1:string[10];
begin
clrscr;
assign(f,'wslog.txt');
assign(f1,'output.txt');
reset(f);
rewrite(f1);
x:=0;
a:=0;
q:=0;
Readln(f,s1);
Repeat
Readln(f,s);
if (s<>s1) and (s1<>'') then {если строки не одинаковы,то считает кол-во запросов в день}
begin
Writeln(f1,s1,' - ',a);
x:=x+a;
a:=0;
s1:=s;
end
else a:=a+1;{иначе суммирует кол-во одинаковых строк}
until eof(f);
Writeln(f1,' vsego zaprosov :');
Writeln(f1,x);
Reset(f);
{S21STR}
Repeat
Readln(f,s2);
a:=pos('S21STR=',s2);
if a<>0 then
begin
a:=a+7;
zap:='';
if S2[a]='' then q:=q+1 else
Repeat
zap:=zap+s2[a]; {считывает послед.символы после 'S21STR=' до &}
a:=a+1;
Until s2[a]='&';
for i:=1 to 1000 do
begin
if zap=zn[i] then begin n[i]:=n[i]+1; break; end;
if zn[i]='' then begin zn[i]:=zap; inc(n[i]); break;
{считает кол-во запросов}
end;
end;
end;
until eof(f);

{S21ALL аналогично}

Repeat
Readln(f,s2);
a:=pos('S21ALL=',s2);
if a<>0 then
begin
a:=a+7;
zap:='';
if s2[a]='' then q:=q+1 else
Repeat
zap:=zap+s2[a];
a:=a+1;
Until s2[a]='&';
for i:=1 to 1000 do
begin
if zap=zn[i] then begin n[i]:=n[i]+1; break; end;
if zn[i]='' then begin zn[i]:=zap; inc(n[i]); break; end;
end;
end;
until eof(f);
{сортирует строки}
for i:=1000 downto 1 do
for j:=1 to i-1 do
if zn[j]>zn[j+1] then
begin {}
m:=zn[j+1]; p:=n[j+1];
zn[j+1]:=zn[j]; n[j+1]:=n[j];
zn[j]:=m; n[j]:=p;
end;
{выводит рез-ты в файл}
writeln(f1,' ',' ',q);{выводит кол-во пустых запрсов}
for i:=1 to 1000 do
if zn[i]<>'' then
writeln(f1,zn[i],' ',n[i]);
close(f);
close(f1);
end.


Нажмите для просмотра прикрепленного файла
IUnknown
Цитата
Проблема в том что у меня во второй части программы (подсчет и сортировка самих текстовых запросов) переполняется массив
проблема возникнет раньше. К примеру, в твоем файле, который прикреплен - строка №1034 является проблемной. Ты прочтешь ее из файла, найдешь в ней подстроку 'S21STR=', а вот символа '&' уже не найдешь. Он вне досягаемости в Турбо-Паскале. Потому что находится на позиции №258 в строке, а прочтешь ты только 255 (больше в String просто не влезет). В итоге получишь банальный вылет программы.

Отсюда первый вопрос: уверен, что хочешь продолжать именно с использованием Турбо-Паскаля, и изобретать костыли, вместо того, чтоб взять нормальный компилятор и начать решать задачу? В зависимости от твоего ответа будем думать дальше: либо как обойти эти ограничения, либо... Какой компилятор использовать взамен (хотя тут, конечно, решение напрашивается само собой)...
Роман
Цитата(IUnknown @ 28.05.2011 20:07) *

проблема возникнет раньше. К примеру, в твоем файле, который прикреплен - строка №1034 является проблемной. Ты прочтешь ее из файла, найдешь в ней подстроку 'S21STR=', а вот символа '&' уже не найдешь. Он вне досягаемости в Турбо-Паскале. Потому что находится на позиции №258 в строке, а прочтешь ты только 255 (больше в String просто не влезет). В итоге получишь банальный вылет программы.

Отсюда первый вопрос: уверен, что хочешь продолжать именно с использованием Турбо-Паскаля, и изобретать костыли, вместо того, чтоб взять нормальный компилятор и начать решать задачу? В зависимости от твоего ответа будем думать дальше: либо как обойти эти ограничения, либо... Какой компилятор использовать взамен (хотя тут, конечно, решение напрашивается само собой)...

ну можно попробовать другой компилятор. Как я понял вы имели ввиду FPC?
IUnknown
Да, я именно его имел в виду. Перекомпилируй свою программу в FPC с ключом {$H+} и увеличенным размером массивов (я сделал
const maxsize = 2000;
// ...
n:array [1..maxsize] of byte;
zn:array [1..maxsize]of string[40];
// и ниже по тексту все 1000 заменил на maxsize

), и чуть-чуть поправь вот этот цикл:

   a:=pos('S21ALL=',s2);
if a<>0 then
begin
a:=a+7;
zap:='';
if s2[a]='' then q:=q+1 else
Repeat
zap:=zap+s2[a];
a:=a+1;
Until s2[a]='&'; // <--- Вот это очень нехорошо...
, если в строке после S21STR не будет амперсанда - будет вылет опять же (такая строка - под номером 205 в твоем файле). Надо в Until добавить условие, чтоб проверялся конец строки:

   Until (a > length(s2)) or (s2[a]='&');
Ну, или запоминать в целочисленной переменной длину строки (чтоб каждый раз ее не вычислять), и сравнивать со значением этой переменной...

Убедись, что программа работает и выдает правильный результат. И когда результат будет правильным, таким, который тебе нужен, замени этот ужасный массив из нескольких тысяч элементов на что-нибудь типа TStringList, там тебе не придется бегать туда-сюда самописными циклами и проверять, есть ли "оно" уже в списке (для этого существуют специальные методы), и занимать это будет ровно столько места, сколько нужно, а не "с огромным запасом".

Хотя, по хорошему, и искать Pos-ом строки в FPC не нужно. Есть регулярные выражения, вытягивать из строки можно что хочешь и как хочешь.
sheka
Цитата
Хотя, по хорошему, и искать Pos-ом строки в FPC не нужно. Есть регулярные выражения, вытягивать из строки можно что хочешь и как хочешь.
Можно подробнее?
IUnknown
Что именно? Про регулярки? Есть модуль regexpr вот в этой папке: \FPC\2.4.2\units\{target}\regexpr, в нем присутствует все необходимое для работы с регэкспами. Можно прикрутить известный дельфийский модуль, если функционала regexpr не хватает.

Согласись, проще за один проход вытащить из строки дату/время/ключевые слова, чем бегать в поисках разных подстрок Pos-ом. А ведь при использовании Pos надо еще найти конец искомого текста, с чем как раз у автора были проблемы. Регулярное выражение от этой необходимости избавляет, сразу будет найден кусок текста, расположенный между определенными словами или символами.
IUnknown
Так... Ну, регэкспы в FPC - такие, что лучше б их вообще не было, поэтому...

...вот что получилось: (Показать/Скрыть)


Всё остальное (всего запросов, количество пустых запросов, что там еще нужно - добавь сам). Кстати, твоя программа некорректно считала количество дат. Посмотри внимательно, сколько строк в логе, и сколько тебе показывает "всего запросов" - увидишь о чем я.
Роман
Спасибо, все перекомпилировал, все работает.

lstQueries.Add(copy (s, start + Length(Tags[ i ]),
finish - start - Length(Tags[ i ])));



Process (lstData, fout, @PrintData);
LstQueries.CustomSort(@MySort);
Process (lstQueries, fout, @PrintQuery);
lstData.Free;
lstQueries.Free;



function MySort(List: TStringList; Index1, Index2: Integer): Integer;
begin
if List[Index1] > List[Index2] then exit(1)
else
if List[Index1] = List[Index2] then exit(0);
exit(-1);
end;


Можно поподробнее как это работает?)
IUnknown
Цитата
Можно поподробнее как это работает?)
Что именно? Функция MySort - это самописная функция сортировки двух строк, которые находятся в StringList-е. Она должна возвращать 0, если строки равны, 1 - если первая строка больше второй, и (-1) - если наоборот, вторая строка больше первой. Потом, такая функция передается параметром в метод CustomSort, и производится сортировка строк StringList-а (все, что надо для сортировки - это знать, нужно ли менять местами 2 строки в определенный момент, так? Вот CustomSort и вызывает переданную ему функцию, чтобы понять, какая из строк больше, и в зависимости от направления сортировки, принимает - или не принимает - решение об обмене их местами). Посмотри исходники CustomSort - станет понятно, что там происходит...

Первый фрагмент - это добавление в список текста запроса. То есть, start - позиция начала одного из тегов, finish - позиция амперсанда (&), процитированная тобой строка вычленит собственно сам запрос (без тега, без знака "=" и без амперсанда), и добавит его в список.

А второй процитированный фрагмент - это сама "соль" программы:
   // для начала - печатаем все даты в файл. Причем для печати
// каждой из них используется функция PrintData.
// Это - потому, что я решил запросы оборачивать кавычками,
// а с датами этого делать не нужно.
Process (lstData, fout, @PrintData);

// Так. Даты напечатаны, теперь переходим к запросам.
// Сначала отсортируем их по алфавиту:
LstQueries.CustomSort(@MySort);

// Теперь уже отсортированный список выводим в тот же файл,
// но уже используя свою функцию, чтоб запросы брались в кавычки
Process (lstQueries, fout, @PrintQuery);

// Ну, и удаляем оба списка, разумеется...
lstData.Free;
lstQueries.Free;
Роман
Спасибо теперь всё окончательно понятноsmile.gif Программа четко выполняет поставленную задачуsmile.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.