标准的URL编码函数?

49

是否有 Delphi 等价于此 .net 方法:

Url.UrlEncode()

注意
我已经好几年没用过 Delphi 了。当我阅读答案时,我注意到有几个备注和替代当前标记的答案。我没有机会测试它们,因此我基于最受欢迎的答案回答。
为了你自己的利益,请稍后查看其他答案,并在决定后投票支持最佳答案,以便每个人都能从你的经验中受益。

13个回答

112

查看 indy IdURI 单元,它在 TIdURI 类中有两个静态方法,用于编码/解码 URL。

uses
  IdURI;

..
begin
  S := TIdURI.URLEncode(str);
//
  S := TIdURI.URLDecode(str);
end;

6
鲍里斯,快点接受这个答案吧,我因为它非常有帮助而给了它一个赞 :) - Peter Perháč
3
@Peter Heh,我没有检查这个问题,因为我不再使用Delphi。但无论如何,这里有你所需要的答案;) - Boris Callens
15
请注意 Marc Durdin 在其博客文章“Indy、TIdURI.PathEncode、URLEncode、ParamsEncode 等警告”中的警告,链接为 http://marc.durdin.net/2012/07/indy-tiduripathencode-urlencode-and.html。 - Jan Doggen
6
Indy出现了问题,因此您需要查看这篇文章: http://marc.durdin.net/2012/07/indy-tiduripathencode-urlencode-and.html - Gabriel
4
自 Delphi XE7 起,您可以使用 TNetEncoding.Url.Encode() 进行编码,这是一种更智能且独立于 Indi 组件的方法。 - Enny
显示剩余3条评论

30

另一个简单的方法是使用HTTPApp单元中的HTTPEncode函数 - 大致如下

Uses 
  HTTPApp;

function URLEncode(const s : string) : string;
begin
  result := HTTPEncode(s);
end

HTTPEncode在Delphi 10.3中已经废弃 - "使用TNetEncoding.URL.Decode"

Uses
  NetEncoding;

function URLEncode(const s : string) : string;
begin
  result := TNetEncoding.URL.Encode(s);
end

1
TNetEncoding.url.encode 无法正确编码 '@' 和其他一些符号 - 使用时请小心。 - fewrandom
1
此外,还有System.Net.URLClient单元,其中包括类函数TURI.UrlEncode class function TURI.URLEncode(const AValue: string; SpacesAsPlus: Boolean): string; - vhanla

15

14

我编写了以下函数,用于编码除非真正安全的字符之外的所有内容。特别是在处理 + 符号时遇到了问题。请注意,您不能使用此函数对整个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;

1
这应该是被接受的答案。(不确定它如何处理UTF-8) - Barry Staes
1
它与Unicode字符存在问题。例如,%633%6CC%628是Unicode字符串“سیب”的结果,它将被解码为“c3lCb8”。 - Mahoor13
1
很棒的答案。毫无疑问,此页面上的所有自定义编码解决方案都应该只编码危险字符,而不是排除安全字符。只有空格和在URI中具有特殊含义的字符需要进行编码。例如,Emb DokWiki 表明“TURLEncoding 仅编码空格(作为加号:+)和以下保留的 URL 编码字符:;:&=+,/?%#[]。”。 - Reversed Engineer

13

另一种选择是使用Synapse库。在SynaCode单元中,该库具有简单的URL编码方法(以及许多其他方法)。

uses
  SynaCode;
..
begin
  s := EncodeUrl( str );
//
  s := DecodeUrl( str );
end;

12

更新于2018年:下面展示的代码似乎已经过时。请参考Remy的评论。

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。


无论如何,Indy不能正常工作,所以你需要看一下这篇文章
http://marc.durdin.net/2012/07/indy-tiduri-pathencode-urlencode-and-paramsencode-and-more/


8
祭坛(Altar)和 Marc Durdin 是对的。TIdURI 已经损坏了。单元 REST.Utils 提供了一个函数 URIEncode,它能够正常工作。 - James Roscoe
1
请注意,上面显示的代码已经过时。TIdURI.ParamsEncode()方法不再是那个样子了。在最新版本中,UnsafeChars包含更多字符,Unicode被正确编码,并且预先存在的%HH序列不会被双重编码。 - Remy Lebeau
@RemyLebeau 我认为,不对预先存在的%HH序列进行编码是一个bug。如果我要求对一个字符串进行编码,那么它应该被编码,无论它是否已经(部分)编码过。例如,字符串'ABC%DE'在TIdURI.Encode中无法正确编码,因为它被返回为原样,而它应该变成'ABC%25DE'。 - Bozzy

6

在最近版本的Delphi中(已测试过XE5),请使用REST.Utils单元中的URIEncode函数。


6

在非dotnet环境下,Wininet单元提供了访问Windows的WinHTTP编码函数的方法: InternetCanonicalizeUrl

请注意,该函数用于规范化URL字符串,以便在HTTP请求中使用。

4

我曾遇到同样的问题(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源代码

(注:本文内容涉及IT技术)

这段代码(以及它的Java源代码)再也不能更低效了 - 哪个程序员会定义这样一个数组而不是计算它呢? - AmigoJack

3

我已经编写了自己的函数。它将空格转换为%20,而不是加号。需要将本地文件路径转换为带有file:///前缀的浏览器路径。最重要的是它可以处理UTF-8字符串。这个函数是基于Radek Hladik上面的解决方案。

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;       

哦,它已在Lazarus中测试过,但也应该适用于Delphi 2010+。 - GAD ZombiE
还需要一个匹配的URLDecode。 - Allan F

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接