Стандартная функция кодирования URL?
Есть ли Delphi-эквивалент этого метода.net:
Url.UrlEncode ()
Заметка
Я не работал с Delphi уже несколько лет. Читая ответы, я замечаю, что есть несколько замечаний и альтернатив для отмеченного в настоящее время ответа. У меня не было возможности протестировать их, поэтому я основываю свой ответ на самых популярных.
Ради себя, проверяйте последующие ответы и после принятия решения поставьте лучший ответ, чтобы каждый мог получить пользу от вашего опыта.
13 ответов
Посмотрите на индийский модуль IdURI, у него есть два статических метода в классе TIdURI для кодирования / декодирования URL.
uses
IdURI;
..
begin
S := TIdURI.URLEncode(str);
//
S := TIdURI.URLDecode(str);
end;
Другой простой способ сделать это - использовать функцию HTTPEncode в модуле HTTPApp - очень грубо
Uses
HTTPApp;
function URLEncode(const s : string) : string;
begin
result := HTTPEncode(s);
end
Начиная с Delphi xe7 вы можете использовать TNetEncoding.Url.Encode()
Я сделал эту функцию для кодирования всего, кроме действительно безопасных символов. Особенно у меня были проблемы с +. Имейте в виду, что вы не можете закодировать весь URL-адрес с помощью этой функции, но вам нужно заключить в части, которые вы хотите, чтобы они не имели особого значения, как правило, значения переменных.
function MyEncodeUrl(source:string):string;
var i:integer;
begin
result := '';
for i := 1 to length(source) do
if not (source[i] in ['A'..'Z','a'..'z','0','1'..'9','-','_','~','.']) then result := result + '%'+inttohex(ord(source[i]),2) else result := result + source[i];
end;
Другой вариант - использовать библиотеку Synapse, которая имеет простой метод кодирования URL (как и многие другие) в модуле SynaCode.
uses
SynaCode;
..
begin
s := EncodeUrl( str );
//
s := DecodeUrl( str );
end;
Обновление 2018: код, показанный ниже, кажется устаревшим. см. комментарий Реми.
class function TIdURI.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}
end else begin
Result := Result + ASrc[i];
end;
end;
end;
Из Инди.
В любом случае, Indy не работает должным образом, поэтому вам нужно увидеть эту статью:
http://marc.durdin.net/2012/07/indy-tiduri-pathencode-urlencode-and-paramsencode-and-more/
В последних версиях Delphi (протестировано с XE5) используйте функцию URIEncode в модуле REST.Utils.
В среде, отличной от dotnet, модуль Wininet обеспечивает доступ к функции кодирования WinHTTP в Windows: InternetCanonicalizeUrl
Я также столкнулся с той же проблемой (Delphi 4).
Я решил проблему, используя ниже упомянутую функцию:
function fnstUrlEncodeUTF8(stInput : widestring) : string;
const
hex : array[0..255] of string = (
'%00', '%01', '%02', '%03', '%04', '%05', '%06', '%07',
'%08', '%09', '%0a', '%0b', '%0c', '%0d', '%0e', '%0f',
'%10', '%11', '%12', '%13', '%14', '%15', '%16', '%17',
'%18', '%19', '%1a', '%1b', '%1c', '%1d', '%1e', '%1f',
'%20', '%21', '%22', '%23', '%24', '%25', '%26', '%27',
'%28', '%29', '%2a', '%2b', '%2c', '%2d', '%2e', '%2f',
'%30', '%31', '%32', '%33', '%34', '%35', '%36', '%37',
'%38', '%39', '%3a', '%3b', '%3c', '%3d', '%3e', '%3f',
'%40', '%41', '%42', '%43', '%44', '%45', '%46', '%47',
'%48', '%49', '%4a', '%4b', '%4c', '%4d', '%4e', '%4f',
'%50', '%51', '%52', '%53', '%54', '%55', '%56', '%57',
'%58', '%59', '%5a', '%5b', '%5c', '%5d', '%5e', '%5f',
'%60', '%61', '%62', '%63', '%64', '%65', '%66', '%67',
'%68', '%69', '%6a', '%6b', '%6c', '%6d', '%6e', '%6f',
'%70', '%71', '%72', '%73', '%74', '%75', '%76', '%77',
'%78', '%79', '%7a', '%7b', '%7c', '%7d', '%7e', '%7f',
'%80', '%81', '%82', '%83', '%84', '%85', '%86', '%87',
'%88', '%89', '%8a', '%8b', '%8c', '%8d', '%8e', '%8f',
'%90', '%91', '%92', '%93', '%94', '%95', '%96', '%97',
'%98', '%99', '%9a', '%9b', '%9c', '%9d', '%9e', '%9f',
'%a0', '%a1', '%a2', '%a3', '%a4', '%a5', '%a6', '%a7',
'%a8', '%a9', '%aa', '%ab', '%ac', '%ad', '%ae', '%af',
'%b0', '%b1', '%b2', '%b3', '%b4', '%b5', '%b6', '%b7',
'%b8', '%b9', '%ba', '%bb', '%bc', '%bd', '%be', '%bf',
'%c0', '%c1', '%c2', '%c3', '%c4', '%c5', '%c6', '%c7',
'%c8', '%c9', '%ca', '%cb', '%cc', '%cd', '%ce', '%cf',
'%d0', '%d1', '%d2', '%d3', '%d4', '%d5', '%d6', '%d7',
'%d8', '%d9', '%da', '%db', '%dc', '%dd', '%de', '%df',
'%e0', '%e1', '%e2', '%e3', '%e4', '%e5', '%e6', '%e7',
'%e8', '%e9', '%ea', '%eb', '%ec', '%ed', '%ee', '%ef',
'%f0', '%f1', '%f2', '%f3', '%f4', '%f5', '%f6', '%f7',
'%f8', '%f9', '%fa', '%fb', '%fc', '%fd', '%fe', '%ff');
var
iLen,iIndex : integer;
stEncoded : string;
ch : widechar;
begin
iLen := Length(stInput);
stEncoded := '';
for iIndex := 1 to iLen do
begin
ch := stInput[iIndex];
if (ch >= 'A') and (ch <= 'Z') then
stEncoded := stEncoded + ch
else if (ch >= 'a') and (ch <= 'z') then
stEncoded := stEncoded + ch
else if (ch >= '0') and (ch <= '9') then
stEncoded := stEncoded + ch
else if (ch = ' ') then
stEncoded := stEncoded + '+'
else if ((ch = '-') or (ch = '_') or (ch = '.') or (ch = '!') or (ch = '*')
or (ch = '~') or (ch = '\') or (ch = '(') or (ch = ')')) then
stEncoded := stEncoded + ch
else if (Ord(ch) <= $07F) then
stEncoded := stEncoded + hex[Ord(ch)]
else if (Ord(ch) <= $7FF) then
begin
stEncoded := stEncoded + hex[$c0 or (Ord(ch) shr 6)];
stEncoded := stEncoded + hex[$80 or (Ord(ch) and $3F)];
end
else
begin
stEncoded := stEncoded + hex[$e0 or (Ord(ch) shr 12)];
stEncoded := stEncoded + hex[$80 or ((Ord(ch) shr 6) and ($3F))];
stEncoded := stEncoded + hex[$80 or ((Ord(ch)) and ($3F))];
end;
end;
result := (stEncoded);
end;
источник: исходный код Java
Я сделал свою собственную функцию. Он преобразует пробелы в%20, а не в знак плюс. Необходимо было преобразовать локальный путь к файлу для браузера (с префиксом file:///). Наиболее важным является то, что он обрабатывает строки UTF-8. Это было вдохновлено решением Радека Хладика выше.
function URLEncode(s: string): string;
var
i: integer;
source: PAnsiChar;
begin
result := '';
source := pansichar(s);
for i := 1 to length(source) do
if not (source[i - 1] in ['A'..'Z', 'a'..'z', '0'..'9', '-', '_', '~', '.', ':', '/']) then
result := result + '%' + inttohex(ord(source[i - 1]), 2)
else
result := result + source[i - 1];
end;
TIdUri или HTTPEncode имеют проблемы с наборами символов Юникода. Функция ниже сделает правильную кодировку для вас.
function EncodeURIComponent(const ASrc: string): UTF8String;
const
HexMap: UTF8String = '0123456789ABCDEF';
function IsSafeChar(ch: Integer): Boolean;
begin
if (ch >= 48) and (ch <= 57) then Result := True // 0-9
else if (ch >= 65) and (ch <= 90) then Result := True // A-Z
else if (ch >= 97) and (ch <= 122) then Result := True // a-z
else if (ch = 33) then Result := True // !
else if (ch >= 39) and (ch <= 42) then Result := True // '()*
else if (ch >= 45) and (ch <= 46) then Result := True // -.
else if (ch = 95) then Result := True // _
else if (ch = 126) then Result := True // ~
else Result := False;
end;
var
I, J: Integer;
ASrcUTF8: UTF8String;
begin
Result := ''; {Do not Localize}
ASrcUTF8 := UTF8Encode(ASrc);
// UTF8Encode call not strictly necessary but
// prevents implicit conversion warning
I := 1; J := 1;
SetLength(Result, Length(ASrcUTF8) * 3); // space to %xx encode every byte
while I <= Length(ASrcUTF8) do
begin
if IsSafeChar(Ord(ASrcUTF8[I])) then
begin
Result[J] := ASrcUTF8[I];
Inc(J);
end
else if ASrcUTF8[I] = ' ' then
begin
Result[J] := '+';
Inc(J);
end
else
begin
Result[J] := '%';
Result[J+1] := HexMap[(Ord(ASrcUTF8[I]) shr 4) + 1];
Result[J+2] := HexMap[(Ord(ASrcUTF8[I]) and 15) + 1];
Inc(J,3);
end;
Inc(I);
end;
SetLength(Result, J-1);
end;
Я хотел бы отметить, что если вас больше заботит правильность, чем эффективность, самое простое, что вы можете сделать, - это закодировать каждый символ в шестнадцатеричном формате, даже если в этом нет особой необходимости.
Только сегодня мне нужно было закодировать несколько параметров для отправки основной формы входа в HTML. Пройдя все варианты, каждый со своими оговорками, я решил написать эту наивную версию, которая отлично работает:
function URLEncode(const AStr: string): string;
var
LBytes: TBytes;
LIndex: Integer;
begin
Result := '';
LBytes := TEncoding.UTF8.GetBytes(AStr);
for LIndex := Low(LBytes) to High(LBytes) do
Result := Result + '%' + IntToHex(LBytes[LIndex], 2);
end;