Добрый вечер! Пытаюсь сделать свои функции URLDecode и URLEncode - использование idURI из Indy 10 прибавляет 50Кб к конечному файлу.
Взял эти функции из idURI.pas и осталось:
function URLDecode(ASrc: string): string;
var
i: integer;
ESC: string[2];
CharCode: integer;
begin
Result := ''; {Do not Localize}
i := 1;
while i <= Length(ASrc) do begin
if ASrc[i] <> '%' then begin {do not localize}
Result := Result + ASrc[i]
end else begin
Inc(i); // skip the % char
ESC := Copy(ASrc, i, 2); // Copy the escape code
Inc(i, 1); // Then skip it.
try
CharCode := StrToInt('$' + ESC); {do not localize}
Result := Result + Char(CharCode);
except end;
end;
Inc(i);
end;
end;
function CharIsInSet(const AString: string; const ACharPos: Integer; const ASet: String): Boolean;
begin
if ACharPos > Length(AString) then begin
Result := False;
end else begin
Result := Pos(AString[ACharPos], ASet)>0;
end;
end;
function CharRange(const AMin, AMax : Char): String;
var i : Char;
begin
Result := '';
for i := Amin to AMax do
begin
Result := Result + i;
end;
end;
function ParamsEncode(const ASrc: string): string;
var
i: Integer;
const
UnsafeChars = '*#%<> []'; {do not localize}
begin
Result := ''; {Do not Localize}
for i := 1 to Length(ASrc) do
begin
if ((CharIsInSet(ASrc, i, UnsafeChars)) or (not (CharIsInSet(ASrc, i, CharRange(#33,#128))))) then
begin {do not localize}
Result := Result + '%' + IntToHex(Ord(ASrc[i]), 2); {do not localize} // (1)
end
else
begin
Result := Result + ASrc[i];
end;
end;
end;
class function PathEncode(const ASrc: string): string;
const
UnsafeChars = '*#%<>+ []'; {do not localize}
var
i: Integer;
begin
Result := ''; {Do not Localize}
for i := 1 to Length(ASrc) do begin
if (CharIsInSet(ASrc, i, UnsafeChars)) or (ASrc[i] >= #$80) or (ASrc[i] < #32) then begin
Result := Result + '%' + IntToHex(Ord(ASrc[i]), 2); {do not localize}
end else begin
Result := Result + ASrc[i];
end;
end;
end;
function URLEncode(const ASrc: string): string;
var i: Integer;
begin
Result := '';
try
i := LastDelimiter('/', ASrc);
Result := PathEncode(Copy(ASrc, 0, i) + ParamsEncode(Copy(ASrc, i+1, Length(ASrc)-i)));
finally
end;
end;
Функции Sys.IntToHex, Sys.IntToStr, IndyPos заменил на IntToHex, IntToStr, Pos. Вроде определения этих функций не отличаются от стандартных.
Но, строка (1) выдает все русские символы не как %NN, а с каким-то непонятным префиксом %D1. Русская "р" конвертируется вообще непонятно во что.
В чем моя ошибка?
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
02-07-2008 15:07
Товарищи, написал следующий код для URLEncode (точнее - взял чужой и несколько изменил/дополнил).
Надеюсь, Вы сможете его проверить -
function ParamsEncode(const AStr: String): String;
const
NoConversion = ['0'..'9','A'..'Z','a'..'z'];
var
Sp, Rp: PChar;
ParmName: Boolean;
begin
SetLength(Result, Length(AStr) * 3);
Sp := PChar(AStr);
Rp := PChar(Result);
ParmName := False;
while Sp^ <> #0 do
begin
if (Sp^ = '?') or (Sp^ = '&') and (ParmName = false) then
ParmName := true;
if (Sp^ = '=') and (ParmName = true) then
begin
Rp^ := Sp^;
Inc(Rp);
Inc(Sp);
ParmName := false;
end;
if ParmName or (Sp^ in NoConversion) then
Rp^ := Sp^
else
begin
FormatBuf(Rp^, 3, '%%%.2x', 6, [Ord(Sp^)]);
Inc(Rp,2);
end;
Inc(Rp);
Inc(Sp);
end;
SetLength(Result, Rp - PChar(Result));
end;
function URLEncode(const ASrc: string): string;
var i: Integer;
begin
Result := '';
try
i := Pos('?', ASrc)-1;
if i>0 then
Result := Copy(ASrc, 0, i) + ParamsEncode(Copy(ASrc, i+1, Length(ASrc)-i))
else
Result := ASrc;
finally
end;
end;
Python,
спасибо огромное! про метод в indy я, естественно, знаю (код, что я привел в примере, - и есть код реализации этого метода из исходников indy). try - из оригинального кода.
02-05-2008 12:33 | Комментарий к предыдущим ответам
Кстати, для Indy есть и штатный метод работы с URLEncode. Его формат: AURLString := TIdURI.URLEncode(AString); Но я им никогда не пользовался. Когда писал »вопрос КС №38145« сделал свою реализацию, а потом, когда узнал про штатный метод, на него переходить так и не стал. Но считаю нужным оповестить Вас о существовании такого метода.
>>> а как правильно?
Ну на правильность не претендую, но примерно так:
function MyURLEncode(const S:string):string;
Const UnsafeChars=[#0..#32,'*','#','%','<','>','[',']',#128..#255];
HexChar='0123456789ABCDEF';
var I,J:integer;
begin
SetLength(Result,3*Length(S)); // maximal possible length
J:=1;For I:=1 to Length(S) do
if S[I] in UnsafeChars then begin
Result[J]:='%';
Result[J+1]:=HexChar[succ(ord(S[I])shr 4)];
Result[J+2]:=HexChar[succ(ord(S[I])and $F)];
Inc(J,3);
end else begin Result[J]:=S[I];Inc(J);end;
SetLength(Result,pred(J));
end;
function MyURLDecode(const S:string):string;
const HexChar='0123456789ABCDEF';
var I,J:integer;
begin
SetLength(Result,Length(S));
I:=1;J:=1;while(I<=Length(S)) do begin
if(S[I]='%')and(I+2<Length(S))then begin // here you must check, that 2 characters left
Result[J]:=chr(((pred(Pos(S[I+1],HexChar)))shl 4)or(pred(Pos(S[I+2],HexChar))));
Inc(I,2);
end else Result[J]:=S[I];
Inc(I);
Inc(J);
end;
SetLength(Result,pred(J));
end;
Пример использования:
procedure TForm1.Button1Click(Sender: TObject);
var S:string;
begin
S:='Превед, медвед!!! Hello, bear!!!';
ShowMessage(S);
S:=MyURLEncode(S);
ShowMessage(S);
S:=MyURLDecode(S);
ShowMessage(S);
end;
Ну и наконец, непонятно, что же там у Вас за try...finally - код внутри исключений не вызывает.
>>> А вы в курсе, что каждое Result:=Result+... приводит к перераспределению памяти, что очень медленно?
а как правильно?
>>> И почему бы не почитать исходники - Indy ведь поставляется в исходниках, разве не так?
так этот код (слегка измененный) и есть из исходников Indy. вопрос в том, что я неправильно изменил.
кстати Result:=Result+... в исходниках Indy и есть
>>> idURI из Indy 10 прибавляет 50Кб к конечному файлу
Файлу какого размера? Если отправлять файл на 10 байт - те же 50 килобайт пришиваются, или все-таки меньше? А вы в курсе, что каждое Result:=Result+... приводит к перераспределению памяти, что очень медленно? И почему бы не почитать исходники - Indy ведь поставляется в исходниках, разве не так?
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.