Такая "работа" конечно быстрой быть не может.
Если сделать нормально - будет на порядок быстрее
Добавлено спустя 1 час 43 минуты 28 секунд:Вот собственно что у меня получилось:
- Код: Выделить всё
program encodetest;
uses
sysutils;
type
TDoNotEncodeUsASCIICharsSet = set of Char;
function StrToPercentTriplet(const Str: string; const DoNotEncodeUsASCIICharsSet: TDoNotEncodeUsASCIICharsSet = []): string;
var
i: integer;
ByteValue: integer;
begin
Result := '';
for i := 1 to Length(Str) do
begin
ByteValue := ord(Str[i]);
if (ByteValue < 128) and (Str[i] in DoNotEncodeUsASCIICharsSet) then
Result := Result + Str[i] else
Result := Result + '%' + IntToHex(ByteValue, 2);
end;
end;
function StrToUrl(const Str: string): string;
const
UnreservedCharacters: set of Char = ['A'..'Z', 'a'..'z', '0'..'9', '-', '.', '_', '~'];
begin
Result := StrToPercentTriplet(Str, UnreservedCharacters);
end;
function FastStrToPercentTriplet(const Str: string;var ResultString:string; const DoNotEncodeUsASCIICharsSet: TDoNotEncodeUsASCIICharsSet = []): integer;
const
_Hex:array[0..15] of char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
i: integer;
ByteValue: byte;
begin
result:=1;
for i := 1 to Length(Str) do
begin
ByteValue := ord(Str[i]);
if (ByteValue < 128) and (Str[i] in DoNotEncodeUsASCIICharsSet)
then
begin
if length(ResultString)>0 then
ResultString[result]:=Str[i];
inc(result);
end
else
begin
if length(ResultString)>0
then
begin
ResultString[result]:='%';
inc(result);
ResultString[result]:=_Hex[(ByteValue and $f0) shr 4];
inc(result);
ResultString[result]:=_Hex[ByteValue and $0f];;
inc(result);
end
else
inc(result,3);
end;
end;
end;
function FastStrToUrl(const Str: string;var ResultString:string): string;
const
UnreservedCharacters: set of Char = ['A'..'Z', 'a'..'z', '0'..'9', '-', '.', '_', '~'];
var
Resultlength:integer;
begin
ResultString:='';
Resultlength := FastStrToPercentTriplet(Str,ResultString,UnreservedCharacters);
setlength(ResultString,Resultlength);
FastStrToPercentTriplet(Str,ResultString,UnreservedCharacters);
end;
function CallLevNikolayevichTolstoy:string;
var
fhandle,filelength:integer;
begin
fhandle:=fileopen('warandpeace.txt',fmShareDenyNone);
filelength:=FileSeek(fhandle,0,2);
FileSeek(fhandle,0,0);
setlength(result,filelength);
FileRead(fhandle,result[1],filelength);
fileclose(fhandle)
end;
var
WarAndPeace,EncodedWarAndPeace:string;
Time:TDateTime;
begin
WarAndPeace:=CallLevNikolayevichTolstoy;
time:=now;
EncodedWarAndPeace:=StrToUrl(WarAndPeace);
writeln('StrToUrl ',((now-time)*10e4):2:3,'sec');
EncodedWarAndPeace:='';
time:=now;
EncodedWarAndPeace:=FastStrToUrl(WarAndPeace,EncodedWarAndPeace);
writeln('FastStrToUrl ',((now-time)*10e4):2:3,'sec');
end.
Преобразование байта в хекс сделано навскидку, не прверял, если и неправильно - на скорость это не влияет. Рядом с ексешником должен лежать файл warandpeace.txt с чемто большим в UTF8, я для теста юзал войну и мир Толстого.
результат налицо))
E:\encodetest>encodetest.exe
StrToUrl 0.279sec
FastStrToUrl 0.020sec
Смысл в том чтоб не прибавлять по байтику, а сделать 2 прохода. в первом посчитать длину строки с результатом, во втором присваивать байтики в уже созданую строку