![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Добрый день. Есть функция удаления подстроки типа <gg hhh>jjjj</gg> из строки
(на самом деле посимвольное копирование когда это не запрещено условием) Код:
function DelUseless(const Data:string):string;
var
Len,I,EndTeg,Differ,J:integer;
DefineTeg:string; (*первые N символов после <*)
begin
Len:=Length(Data);
SetLength(Result, Len);
Differ:=0;
J:=0;
if Length(Data) = 0 then Exit else
for I := 1 to Length(Data) do
(*-----------------ЦИКЛ-----------------------------*)
begin
if Differ > 0 then Dec(Differ)
else
if (Data[i] = '<') then
begin
DefineTeg:=Copy(Data, I,10); (*тут тормоз?*)
if (PosEx('<script', DefineTeg,1)= 0) then
begin
Inc(J);
Result[J]:=Data[i];
end
else
begin
EndTeg:=PosEx('</script>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 8);
end
end
else
begin
Inc(J);
Result[J]:=Data[i];
end
end;
(*-----------------конец-----------------------------*)
SetLength(Result, J);
end; (*все работает*)функция работает достаточно быстро (файл 3 мб за 30 мС обрабатывает) но есть подозрение, что использование COPY (DefineTeg:=Copy(Data, I,10) увеличивает время обработкиВнимание!! Вопрос: 1. действительно ли COPY не самое лучшее решение по быстродействию 2. чем можно заменить COPY? может вставка на ASM? |
|
#2
|
|||
|
|||
|
а разве Copy уже не написана на асме?
не заморачивайся) 30мсек |
|
#3
|
||||
|
||||
|
Вообще не понимаю использования PosEx для сравнения строк.
|
|
#4
|
||||
|
||||
|
тут проблема не в Copy, а в алгоритме.
|
|
#5
|
|||
|
|||
|
Цитата:
если можно поподробнее. ведь в букваре сказано: функция для поиска в строке, именуемая PosEx. |
|
#6
|
||||
|
||||
|
Зачем искать в строке, когда можно просто сравнить строки на равенство? Копировать не 10 символов, а 7 (длина строки "<script"), а затем сравнить копированную строку со "<script" обычным "равно".
Вообще NumLock прав. Не понимаю этих плясок с бубном вокруг цикла for, когда гораздо быстрее было бы сделать while, на котором лишние итерации можно просто пропустить. |
|
#7
|
|||
|
|||
|
тут все немножко сложнее, сейчас функция уже имеет вид
Код:
function DelUseless(const Data:string):string;
const
Teg1 = '<script'; Teg2 = '<style'; Teg3 = '<noscript'; Teg4 = '<applet';
Teg5 = '<object'; Teg6 = '<textarea'; Teg7 = '<audio'; Teg8 = '<button';
Teg9 = '<canvas'; Teg10 = '<comment'; Teg11 = '<datalist'; Teg12 = '<del';
Teg13 = '<meter'; Teg14 = '<noembed'; Teg15 = '<optgroup'; Teg16 = '<output';
Teg17 = '<progress';
var
Len,I,EndTeg,Differ,J:integer;
DefineTeg:string; (*первые N символов после <*)
Pos1,Pos2:integer;
Pattern:string;
starttime,endtime,q:int64;
begin starttime:=GetTickCount;
Len:=Length(Data);
SetLength(Result, Len);
Differ:=0;
J:=0;
if Length(Data) = 0 then Exit else
for I := 1 to Length(Data) do
(*-----------------ЦИКЛ-----------------------------*)
begin (*2 Cycle*)
if Differ > 0 then Dec(Differ)
else
if Data[i] <> '<' then
begin
Inc(J);
Result[J]:=Data[i]; (**)
end
else
begin
DefineTeg:=Copy(Data, I,11); (*копируем 12 символов*)
Pos1:=PosEx(' ',DefineTeg,1); (*позиция первого пробела *)
if Pos1 = 0 then (*если пробела нет ищем >*)
Pos1:=PosEx('>',DefineTeg,1); (*позиция первого >*)
Pos2:=Pos1-1;
Pattern:=Copy(DefineTeg, 1, Pos2); (*выделяем паттерн тега*)
(*----выбор тега на CASE------------------------*)
case AnsiIndexStr(Pattern,
[Teg1, Teg2, Teg3, Teg4, Teg5, Teg6, Teg7, Teg8, Teg9,
Teg10, Teg11, Teg12, Teg13, Teg14, Teg15, Teg16, Teg17]) of
0:begin
EndTeg:=PosEx('</script>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 8);
end;
1:begin
EndTeg:=PosEx('</style>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 7);
end;
2:begin
EndTeg:=PosEx('</noscript>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
3:begin
EndTeg:=PosEx('</applet>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
4:begin
EndTeg:=PosEx('</object>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
5:begin
EndTeg:=PosEx('</textarea>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
6:begin
EndTeg:=PosEx('</audio>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
7:begin
EndTeg:=PosEx('</button>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
8:begin
EndTeg:=PosEx('</canvas>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
9:begin
EndTeg:=PosEx('</comment>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
10:begin
EndTeg:=PosEx('</datalist>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
11:begin
EndTeg:=PosEx('</del>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
12:begin
EndTeg:=PosEx('</meter>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
13:begin
EndTeg:=PosEx('</noembed>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
14:begin
EndTeg:=PosEx('</optgroup>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
15:begin
EndTeg:=PosEx('</output>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
16:begin
EndTeg:=PosEx('</progress>',Data,I);
if (EndTeg > 0) then Differ:=(EndTeg - I + 10);
end;
else
begin
Inc(J);
Result[J]:=Data[i];
end;
(*------конец CASE------------------------------*)
end;
end;
end;
(*-------конец Цикла-------------------------------------*)
SetLength(Result, J);
endtime:=GetTickCount; q:=endtime-starttime; ShowMessage('TIME = '+IntToStr(q));
end; (*78(три тега) полная набор тегов 218 мС для 3 мб текста*)вот как тут ускорить обработку? может кто подскажет? |
|
#8
|
||||
|
||||
|
Сделать цикл while, убрать этот никому не нужный differ и просто устанавливать i на символ после конца закрывающего тега.
Вообще скорее всего быстрее искать очередной тег, копировать всё до него, искать следующий после конца найденного. Посимвольно дописывать в конец строки - это не гуд. |
|
#9
|
|||
|
|||
|
то есть вначале сделать быструю функцию типа
function Del(const Str,StartTeg,EndTeg:string):string; а потом эту функцию кинуть в цикл, в котором поочередно подставлять в параметры пары тегов и по новой прогонять Str, поочередно удаляя все ненужное? и так будет быстрее чем просто посимвольно скопировать Str в Result, запрещая копирование там где нужно? |
|
#10
|
||||
|
||||
|
Я бы сделал так.
A = 1. Ищу первое вхождение < после A. Копирую 10 символов с этой позиции во временную строку. Смотрю на нужный тег. Если не нужный - ищу следующую < с этой позиции. Если нужный - копирую от A до текущей позиции, ищу к нему закрывающий и A = концу закрывающего. Вернуться в начало. Каждое прибавление символа к строке - это перевыделение памяти под строку. |
|
#11
|
|||
|
|||
|
то есть использовать CASE для определения нужный тег, или не нужный?
и использовать Repeat для одного гарантированного прохода по строке а копировать чем? COPY или MOVE. или через указатели? типа: Код:
function TegsDelete2(const Source: string):string;
var
Step, TagCnt : Integer;
ResChar, SrcChar: PChar;
begin
TagCnt:=0;
SetLength(Result, Length(Source)); (*создаем выход с длинной =*)
if Length(Source)=0 then Exit;
SrcChar:=@Source[1]; (*копировать первый символ указатель на память*)
ResChar:=@Result[1];
for Step:=1 to Length(Source) (*цикл*)
do begin
case SrcChar^ of
'<': Inc(TagCnt);
'>': Dec(TagCnt);
else if TagCnt<=0 then
begin (*вот тут копирование нужных символов*)
ResChar^:=SrcChar^;
Inc(ResChar);
TagCnt:=0
end
end;
Inc(SrcChar)
end;
SetLength(Result, ResChar-PChar(@Result[1])); (*обрезаем лишнее в строке*)
end; |
|
#12
|
||||
|
||||
|
Да, получать первый тег можно тем же кейсом, использовать repeat, копировать copy (ее скорость нормальная). Через указатели - проблем не оберешься.
И причем тут потоки? Если они будут обрабатывать разные строки, то вообще никакой связи. А если одну... лучше так не делать. |
|
#13
|
|||
|
|||
|
Цитата:
Ну вот: Код:
function DelUseless(const Data:string):string;
var
Len,J:integer;
DefineTeg:string; (*первые N символов после <*)
starttime,endtime,q:int64;
Count:integer; (*счетчик позиции символа в строке*)
Pos1:integer; (*позиция вхождения < в строке*)
TegEnd:Integer; (*позиция окончания тега*)
Pattern:string; (*выделенный Тег из строки*)
SubStr:string;
begin starttime:=GetTickCount;
Len:=Length(Data);
J:=0;
if Length(Data) = 0 then Exit else
Count:=1;
(*-----------------ЦИКЛ-----------------------------*)
repeat
Pos1:=PosEx('<', Data,Count); (*поиск первого вхождения символа < в строке*)
if Pos1 = 0 then
begin
if Count = 1 then (*эта ветка на тот случай если вообще нет тегов в странице*)
begin
Result:=Data;
Break;
end else
begin (*эта ветка копирует все после того как закончатся <*)
SubStr:=Copy(Data, Count, Len-Count-1);
J:=Length(SubStr)+Length(Result);
Insert(SubStr, Result, J+1);
Break;
end;
end else
begin (*тут конечно можно проще, но на скорость это не влияет*)
DefineTeg:=Copy(Data, Pos1, 10); (*копируем первые 11 символов с позиции первого вхождения*)
TegEnd:=PosEx(' ',DefineTeg,1); (*позиция первого пробела *)
if TegEnd = 0 then (*если пробела нет ищем >*)
TegEnd:=PosEx('>',DefineTeg,1); (*позиция первого >*)
Pattern:=Copy(DefineTeg, 1, (TegEnd-1)); (*выделяем паттерн тега*)
(*----------------------------------------------------------*)
(*далее определяем есть ли в Перем нужный тег(<script)*)
if Pattern = '<script' then
begin
SubStr:=Copy(Data, Count, Pos1-Count); (*копировать от Count до позиции Pos1*)
J:=Length(SubStr)+Length(Result); (*число символов в ВЫХОДЕ!!!!!*)
Insert(SubStr, Result, J+1);
Count:=PosEx('</script>', Data, Pos1)+9; (*переводим позицию на следующий символ*)
end
else
begin
SubStr :=Copy(Data, Count, Pos1-Count+1); (*копировать все gghh<*)
J:=Length(SubStr)+Length(Result);
Insert(SubStr, Result, J+1);
Count:=Pos1+1; (*переводим позицию на следующий символ*)
end;
end
until Pos1 = 0 ;
(*-----------------конец-----------------------------*)
endtime:=GetTickCount; q:=endtime-starttime; ShowMessage('TIME = '+IntToStr(q));
end; (*все работает 50 мС для 3 мБ*)Если возможно, укажите на узкие участки и как их заменить, но без использования указателей. это пока не совсем понятно и еще косячок: почемуто пропадают два последние символа в строке, было </html> стало </htm, непонятно куда Последний раз редактировалось Pcrepair, 19.02.2013 в 22:40. |
|
#14
|
||||
|
||||
|
Зачем Insert? Можно просто дописать в конец. Что-то вроде
Код:
Count := 1;
cPos := 1;
Pos1:=PosEx('<', Data,1);
Result := '';
while Pos1 > 0 do
begin
DefineTeg:=Copy(Data, Pos1, 10); (*копируем первые 11 символов с позиции первого вхождения*)
TegEnd:=PosEx(' ',DefineTeg,1); (*позиция первого пробела *)
if TegEnd = 0 then (*если пробела нет ищем >*)
TegEnd:=PosEx('>',DefineTeg,1); (*позиция первого >*)
if TegEnd = 0 then
break;
Pattern:=Copy(DefineTeg, 1, (TegEnd-1)); (*выделяем паттерн тега*)
// можно и так, а можно
// SetLength(DefineTag, TegEnd - 1);
// и юзать DefineTag
if Pattern = '<script' then
begin
Result := Result + Copy(Data, Count, Pos1 - Count);
Count := PosEx('</script>', Data, Pos1 + 7) + 9;
cPos1 := Count;
end
else
cPos1 := Pos1 + 1;
Pos1:=PosEx('<', Data,cPos);
end;
Result := Result + Copy(Data, Count, Length(Result) - Count);Хотя вообще странно, что твой вариант медленнее. В таком случае может быть медленнее и тут. По идеи PosEx = rep scasb, одна команда; в то время как прибавление по одному символу - постоянные релоки строки. Последний раз редактировалось Bargest, 19.02.2013 в 23:16. |