delphi XE7 HttpEncode 编码问题

      近期在做网址编码相关的工作,发现在用 XE5 编译的时候,一切正常,拿 到 XE7下 就 结果错误了。百度了下,谷歌 了下,有人提出,但是,我没有找到答案,也许都没有碰到这个问题,也许都己经自己默默的解决了,在此 小记一下,方便后人,也方便自己 查寻。

例子 : 原字符   "过年"

httpencode('过年') 结果 :

XE5为  %B9%FD%C4%EA

XE7 调用 相当函数结果 %E8%BF%87%E5%B9%B4 

百思不得其解啊,折腾了很长时间,后来终于想到是不是 此函数 官方更新修改了,(没办法,人比较笨)

于是查看源码:

XE5的 web.httpapp 中(分string 和 ansistring, 我用ansistring 版本得到 期望的结果):

  1 function HTTPEncode(const AStr: string): string;

  2 // The NoConversion set contains characters as specificed in RFC 1738 and

  3 // should not be modified unless the standard changes.

  4 const

  5   NoConversion = [Ord('A')..Ord('Z'), Ord('a')..Ord('z'), Ord('*'), Ord('@'),

  6                   Ord('.'), Ord('_'), Ord('-'), Ord('0')..Ord('9'), Ord('$'),

  7                   Ord('!'), Ord(''''), Ord('('), Ord(')')];

  8 var

  9   Sp, Rp: PChar;

 10 begin

 11   SetLength(Result, Length(AStr) * 3);

 12   Sp := PChar(AStr);

 13   Rp := PChar(Result);

 14   while Sp^ <> #0 do

 15   begin

 16     if Ord(Sp^) in NoConversion then

 17       Rp^ := Sp^

 18     else

 19       if Sp^ = ' ' then

 20         Rp^ := '+'

 21       else

 22       begin

 23         FormatBuf(Rp, 3, string('%%%.2x'), 6, [Ord(Sp^)]);

 24         Inc(Rp,2);

 25       end;

 26     Inc(Rp);

 27     Inc(Sp);

 28   end;

 29   SetLength(Result, Rp - PChar(Result));

 30 end;

 31 

 32 function HTTPDecode(const AStr: string): string;

 33 var

 34   Sp, Rp, Cp: PChar;

 35   S: string;

 36 begin

 37   SetLength(Result, Length(AStr));

 38   Sp := PChar(AStr);

 39   Rp := PChar(Result);

 40   Cp := Sp;

 41   try

 42     while Sp^ <> #0 do

 43     begin

 44       case Sp^ of

 45         '+': Rp^ := ' ';

 46         '%': begin

 47                // Look for an escaped % (%%) or %<hex> encoded character

 48                Inc(Sp);

 49                if Sp^ = '%' then

 50                  Rp^ := '%'

 51                else

 52                begin

 53                  Cp := Sp;

 54                  Inc(Sp);

 55                  if (Cp^ <> #0) and (Sp^ <> #0) then

 56                  begin

 57                    S := Char('$') + Cp^ + Sp^;

 58                    Rp^ := Char(StrToInt(string(S)));

 59                  end

 60                  else

 61                    raise EWebBrokerException.CreateFmt(sErrorDecodingURLText, [Cp - PChar(AStr)]);

 62                end;

 63              end;

 64       else

 65         Rp^ := Sp^;

 66       end;

 67       Inc(Rp);

 68       Inc(Sp);

 69     end;

 70   except

 71     on E:EConvertError do

 72       raise EConvertError.CreateFmt(sInvalidURLEncodedChar,

 73         [Char('%') + Cp^ + Sp^, Cp - PChar(AStr)])

 74   end;

 75   SetLength(Result, Rp - PChar(Result));

 76 end;

 77 

 78 function HTTPEncode(const AStr: AnsiString): AnsiString;

 79 // The NoConversion set contains characters as specificed in RFC 1738 and

 80 // should not be modified unless the standard changes.

 81 const

 82   NoConversion = ['A'..'Z','a'..'z','*','@','.','_','-',

 83                   '0'..'9','$','!','''','(',')'];

 84 var

 85   Sp, Rp: PAnsiChar;

 86 begin

 87   SetLength(Result, Length(AStr) * 3);

 88   Sp := PAnsiChar(AStr);

 89   Rp := PAnsiChar(Result);

 90   while Sp^ <> #0 do

 91   begin

 92     if Sp^ in NoConversion then

 93       Rp^ := Sp^

 94     else

 95       if Sp^ = ' ' then

 96         Rp^ := '+'

 97       else

 98       begin

 99         System.AnsiStrings.FormatBuf(Rp^, 3, AnsiString('%%%.2x'), 6, [Ord(Sp^)]);

100         Inc(Rp,2);

101       end;

102     Inc(Rp);

103     Inc(Sp);

104   end;

105   SetLength(Result, Rp - PAnsiChar(Result));

106 end;
View Code

在XE7中

web.httpapp:

function HTTPEncode(const AStr: string): string;

begin

  Result := TNetEncoding.URL.Encode(AStr);

end;

查看 system.netencoding

找到 

function TNetEncoding.DoEncode(const Input: array of Byte): TBytes;

begin

  Result := TEncoding.UTF8.GetBytes(DoEncode(TEncoding.UTF8.GetString(@Input[0])));

end;
查看类定义:  
TURLEncoding = class(TNetEncoding) protected function DoDecode(const Input: string): string; overload; override; function DoEncode(const Input: string): string; overload; override; end;
查看函数代码:
function TURLEncoding.DoEncode(const Input: string): string;

// The NoConversion set contains characters as specificed in RFC 1738 and

// should not be modified unless the standard changes.

const

  NoConversion = [Ord('A')..Ord('Z'), Ord('a')..Ord('z'), Ord('*'), Ord('@'),

                  Ord('.'), Ord('_'), Ord('-'), Ord('0')..Ord('9'), Ord('$'),

                  Ord('!'), Ord(''''), Ord('('), Ord(')')];



  procedure AppendByte(B: Byte; var Buffer: PChar);

  const

    Hex = '0123456789ABCDEF';

  begin

    Buffer[0] := '%';

    Buffer[1] := Hex[B shr 4 + Low(string)];

    Buffer[2] := Hex[B and $F + Low(string)];

    Inc(Buffer, 3);

  end;



var

  Sp, Rp: PChar;

  MultibyteChar: TBytes;

  I, ByteCount: Integer;

begin

  // Characters that require more than 1 byte are translated as "percent-encoded byte"

  // which will be encoded with 3 chars per byte -> %XX

  // Example: ?character

  //   Multibyte representation: C391 (2 bytes)

  //   URL encode representation: %C3%91

  //

  // So the worst case is 4 bytes(max) per Char, and 3 characters to represent each byte

  SetLength(Result, Length(Input) * 4 * 3);

  Sp := PChar(Input);

  Rp := PChar(Result);

  SetLength(MultibyteChar, 4);

  while Sp^ <> #0 do

  begin

    if Ord(Sp^) in NoConversion then

    begin

      Rp^ := Sp^;

      Inc(Rp)

    end

    else if Sp^ = ' ' then

    begin

      Rp^ := '+';

      Inc(Rp)

    end

    else

    begin

      if (Ord(Sp^) < 128) then

        // Single byte char

        AppendByte(Ord(Sp^), Rp)

      else

      begin

        // Multi byte char

        ByteCount := TEncoding.UTF8.GetBytes([Sp^], 0, 1, MultibyteChar, 0);

        for I := 0 to ByteCount - 1 do

          AppendByte(MultibyteChar[I], Rp);

      end

    end;

    Inc(Sp);

  end;

  SetLength(Result, Rp - PChar(Result));

end;
View Code

似乎有点不同。

目前是我自己建立一个函数 ,复制XE5版本的 代码 放在XE7里面调用,得到希望的结果的。

代码:

function MyHTTPEncode(const AStr: AnsiString): AnsiString;

// The NoConversion set contains characters as specificed in RFC 1738 and

// should not be modified unless the standard changes.

const

  NoConversion = ['A'..'Z','a'..'z','*','@','.','_','-',

                  '0'..'9','$','!','''','(',')'];

var

  Sp, Rp: PAnsiChar;

begin

  SetLength(Result, Length(AStr) * 3);

  Sp := PAnsiChar(AStr);

  Rp := PAnsiChar(Result);

  while Sp^ <> #0 do

  begin

    if Sp^ in NoConversion then

      Rp^ := Sp^

    else

      if Sp^ = ' ' then

        Rp^ := '+'

      else

      begin

        System.AnsiStrings.FormatBuf(Rp^, 3, AnsiString('%%%.2x'), 6, [Ord(Sp^)]);

        Inc(Rp,2);

      end;

    Inc(Rp);

    Inc(Sp);

  end;

  SetLength(Result, Rp - PAnsiChar(Result));

end;
View Code

 

你可能感兴趣的:(Delphi)