【问题标题】:Standard URL encode function?标准的 URL 编码功能?
【发布时间】:2010-10-21 01:12:28
【问题描述】:

是否有与此.net 方法等效的 Delphi:

Url.UrlEncode()

注意
我已经好几年没有与 Delphi 合作了。 当我阅读答案时,我注意到当前标记的答案有几个评论和替代方案。我没有机会测试它们,所以我的答案基于最受好评的。
为了您自己,请检查以后的答案,并在决定为最佳答案投票后,让每个人都可以从您的经验中受益。

【问题讨论】:

    标签: delphi


    【解决方案1】:

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

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

    【讨论】:

    • 鲍里斯,来吧,接受这个答案,我只是给它一个完全有帮助的点:)
    • @Peter Heh,我没有检查这个问题,因为我不再使用 Delphi。但不管怎样,你去吧;)
    • 但请注意 Marc Durdin 的博客文章“Indy、TIdURI.PathEncode、URLEncode 和 ParamsEncode 等”中的警告,地址为 marc.durdin.net/2012/07/…
    • Indy 无法正常工作,因此您需要查看这篇文章:marc.durdin.net/2012/07/…
    • 从 Delphi xe7 开始,您可以使用 TNetEncoding.Url.Encode(),这是一种更智能的方式,并且独立于 Indi Components
    【解决方案2】:

    另一种简单的方法是使用 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
    

    【讨论】:

    • TNetEncoding.url.encode 没有正确编码 '@' 和其他几个符号 - 小心它
    • 还有System.Net.URLClient单元,包含类函数TURI.UrlEncode class function TURI.URLEncode(const AValue: string; SpacesAsPlus: Boolean): string;
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      我自己做了这个函数来编码除了真正安全的字符之外的所有内容。特别是我遇到了+的问题。请注意,您不能使用此函数对整个 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;
      

      【讨论】:

      • 这应该是公认的答案。 (不确定它如何处理 UTF-8)
      • Unicode 字符有问题。例如。 %633%6CC%628 是 unicode 字符串 'سیب' 的结果,它将被解码为 'c3lCb8'
      • 很好的答案。当然,这个页面上的所有自定义编码解决方案都应该只编码危险字符,而不是排除安全字符。只有空格和 URI 中具有特殊含义的字符需要编码。例如。 Emb DokWiki 说“TURLEncoding 只编码空格(加号:+)和以下保留的 URL 编码字符:;:&=+,/?%#[]。”
      【解决方案5】:

      由于Delphi xe7可以使用TNetEncoding.Url.Encode()

      【讨论】:

        【解决方案6】:

        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/

        【讨论】:

        • Altar 和 Marc Durdin 是对的。 TIdURI 坏了。 Unit REST.Utils 提供了一个可以正常工作的函数 URIEncode。
        • 仅供参考,上面显示的代码是旧的。这不再是TIdURI.ParamsEncode() 的样子了。在最新版本中,UnsafeChars 中包含更多字符,Unicode 编码正确,并且预先存在的%HH 序列没有双重编码。
        • @RemyLebeau 预先存在的 %HH 序列未编码的事实是一个错误,恕我直言。如果我要求对字符串进行编码,无论如何都应该对其进行编码,无论它是否已经(部分)编码。例如,字符串 'ABC%DE' 在 TIdURI.Encode 中没有正确编码,因为它按原样返回,而它应该变成 'ABC%25DE'。
        【解决方案7】:

        在非 dotnet 环境中,Wininet 单元提供对 Windows 的 WinHTTP 编码功能的访问: InternetCanonicalizeUrl

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            【解决方案9】:

            我也面临同样的问题(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 source code

            【讨论】:

            • 这段代码(以及它的 Java 起源)效率再低下——哪个程序员会定义这样一个数组而不是计算它?
            【解决方案10】:

            我已经做了我自己的功能。它将空格转换为 %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+ 中也应该可以工作。
            【解决方案11】:

            AFAIK 你需要自己制作。

            这是一个例子。

            【讨论】:

              【解决方案12】:

              TIdUri 或 HTTPEncode 存在 unicode 字符集问题。下面的函数将为您进行正确的编码。

              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;
              

              【讨论】:

              【解决方案13】:

              我想指出,如果您更关心正确性而不是效率,那么您可以做的最简单的事情就是对每个字符进行十六进制编码,即使这不是绝对必要的。

              就在今天,我需要为基本的 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;
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-10-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多