【问题标题】:Is there a Delphi standard function for escaping HTML?是否有用于转义 HTML 的 Delphi 标准函数?
【发布时间】:2010-06-03 16:55:26
【问题描述】:

我有一个报告,它应该采用网格控件并生成 HTML 输出。网格中的一列可以显示任意数量的值,或<Any>。当然,当它输出到 HTML 时,它最终是空白的。

我可能会编写一些例程来使用 StringReplace 将其转换为<Any>,以便正确显示此特殊情况,但我认为 RTL 中可能有一个已经过测试并且正确的地方。谁知道我在哪里可以找到它?

【问题讨论】:

  • 一种 Delphi 转义 HTML 的方法... Intraweb! ;-)

标签: html delphi escaping


【解决方案1】:

我 99% 确定 RTL 中不存在这样的功能(截至 Delphi 2009)。当然 - 然而 - 编写这样一个函数是微不足道的。

更新

HTTPUtil.HTMLEscape 是您正在寻找的:

function HTMLEscape(const Str: string): string;

我不敢在这里发布代码(可能侵犯版权),但是套路很简单。它将 ""、"&" 和 """ 编码为 <>&"。它还将字符 #92、#160..#255 替换为十进制代码,例如\

如果文件是 UTF-8,则后面的步骤是不必要的,而且也不合逻辑,因为较高的特殊字符(例如 ∮)保持原样,而较低的特殊字符(例如 ×)被编码。

更新 2

针对 Stijn Sanders 的回答,我做了一个简单的性能测试。

program Project1;

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils;

var
  t1, t2, t3, t4: Int64;
  i: Integer;
  str: string;
const
  N = 100000;


function HTMLEncode(const Data: string): string;
var
  i: Integer;
begin

  result := '';
  for i := 1 to length(Data) do
    case Data[i] of
      '<': result := result + '&lt;';
      '>': result := result + '&gt;';
      '&': result := result + '&amp;';
      '"': result := result + '&quot;';
    else
      result := result + Data[i];
    end;

end;

function HTMLEncode2(Data: string):string;
begin
  Result:=
    StringReplace(
    StringReplace(
    StringReplace(
    StringReplace(
      Data,
      '&','&amp;',[rfReplaceAll]),
      '<','&lt;',[rfReplaceAll]),
      '>','&gt;',[rfReplaceAll]),
      '"','&quot;',[rfReplaceAll]);
end;

begin

  QueryPerformanceCounter(t1);
  for i := 0 to N - 1 do
    str := HTMLEncode('Testing. Is 3*4<3+4? Do you like "A & B"');
  QueryPerformanceCounter(t2);

  QueryPerformanceCounter(t3);
  for i := 0 to N - 1 do
    str := HTMLEncode2('Testing. Is 3*4<3+4? Do you like "A & B"');
  QueryPerformanceCounter(t4);

  Writeln(IntToStr(t2-t1));
  Writeln(IntToStr(t4-t3));

  Readln;


end.

输出是

532031
801969

【讨论】:

    【解决方案2】:

    这似乎是一场小型比赛:) 这是另外一个实现:

    function HTMLEncode3(const Data: string): string;
    var
      iPos, i: Integer;
    
      procedure Encode(const AStr: String);
      begin
        Move(AStr[1], result[iPos], Length(AStr) * SizeOf(Char));
        Inc(iPos, Length(AStr));
      end;
    
    begin
      SetLength(result, Length(Data) * 6);
      iPos := 1;
      for i := 1 to length(Data) do
        case Data[i] of
          '<': Encode('&lt;');
          '>': Encode('&gt;');
          '&': Encode('&amp;');
          '"': Encode('&quot;');
        else
          result[iPos] := Data[i];
          Inc(iPos);
        end;
      SetLength(result, iPos - 1);
    end;
    

    更新 1:更新了最初提供的错误代码。

    更新 2:和时代:

    HTMLEncode :   2286508597
    HTMLEncode2:   3577001647
    HTMLEncode3:    361039770
    

    【讨论】:

    • 这是一个非常好的解决方案! (虽然可能有点矫枉过正!:))主要收获可能不是移动,而是您不需要经常为结果分配更多空间的事实。我会给你+1,除非它不是实际问题的答案! :)
    • 好吧,我给你 +1 只是因为它是一个很好的优化示例。
    • (顺便说一句:你知道“内容”和“比赛”之间存在细微差别吗?:))
    • 当然!我对“见面”和“肉”有类似的问题:)
    • 感谢您提供如此快速的例程 - 我必须转换大量数据,这节省了我的时间。
    【解决方案3】:

    我通常只使用这个代码:

    function HTMLEncode(Data:string):string;
    begin
      Result:=
        StringReplace(
        StringReplace(
        StringReplace(
        StringReplace(
        StringReplace(
          Data,
          '&','&amp;',[rfReplaceAll]),
          '<','&lt;',[rfReplaceAll]),
          '>','&gt;',[rfReplaceAll]),
          '"','&quot;',[rfReplaceAll]),
          #13#10,'<br />'#13#10,[rfReplaceAll]);
    end;
    

    (版权?是open source

    【讨论】:

    • 这看起来比简单循环慢很多:for i := 1 to length(Data) do case ord(Data[i]) of ...
    • 我刚刚测试了这个:嵌套字符串替换:801259 滴答声。一个循环:532037 个滴答声。
    • 嗯,有趣,使用 TStringStream 还能获得一些性能吗?
    • 主要的性能窃贼可能是结果字符串的不断重新分配。这可以像 da-soft 的回复一样解决。但是性能对于 OP 来说根本不是问题,因此,它更像是一个有趣的旁注。 :)
    • 无论如何,万分感谢您在这里的输入,我已经修改了我的 HTMLEncode:xxm.svn.sourceforge.net/viewvc/xxm/trunk/Delphi/public/…
    【解决方案4】:

    Unit HTTPApp 有一个名为 HTMLEncode 的函数。它还具有其他与 HTML/HTTP 相关的功能。

    【讨论】:

    【解决方案5】:

    我不知道它是在哪个 delphi 版本中引入的,但是 System.NetEncoding 单元具有:

    TNetEncoding.HTML.Encode
    TNetEncoding.HTML.Decode
    

    函数。阅读here。你不再需要外部库了。

    【讨论】:

      【解决方案6】:

      从单元 Soap.HTTPUtil 或简单的 HTTPUtil 用于旧的 delphi 版本,您可以使用

      function HTMLEscape(const Str: string): string;
      var
        i: Integer;
      begin
        Result := '';
        for i := Low(Str) to High(Str) do
        begin
          case Str[i]  of
          '<' : Result := Result + '&lt;';    { Do not localize }
          '>' : Result := Result + '&gt;';    { Do not localize }
          '&' : Result := Result + '&amp;';   { Do not localize }
          '"' : Result := Result + '&quot;';  { Do not localize }
      {$IFNDEF UNICODE}
          #92, Char(160) .. #255 : Result := Result + '&#' + IntToStr(Ord(Str[ i ])) +';';  { Do not localize }
      {$ELSE}
          // NOTE: Not very efficient
          #$0080..#$FFFF : Result := Result + '&#' + IntToStr(Ord(Str[ i ])) +';'; { Do not localize }
      {$ENDIF}
          else
            Result := Result + Str[i];
          end;
        end;
      end;
      

      【讨论】:

        【解决方案7】:

        这种替换特殊字符的方法怎么样:

            function HtmlWeg(sS: String): String;
        var
          ix,cc: Integer;
          sC, sR: String;
        begin
          result := sS;
          ix := pos('\u00',sS);
        
          while ix >0 do
          begin
            sc := copy(sS,ix+4,2) ;
            cc := StrtoIntdef('$' +sC,32);
            sR := '' + chr(cc);
            sS := Stringreplace(sS, '\u00'+sC,sR,[rfreplaceall]) ;
            ix := pos('\u00',sS);
          end;
          result := sS;
        end;
        

        【讨论】:

        • 此问题中专门询问了标准函数,因此无论正确与否,您的答案都无法回答。
        【解决方案8】:

        我的函数将 for 循环与最小的字符串重新分配相结合:

        function HtmlEncode(const Value: string): string;
        var
          i: Integer;
        
        begin
          Result := Value;
          i := 1;
        
          while i <= Length(Result) do
          begin
            if Result[i] = '<' then
            begin
              Result[i] := '&';
              Insert('lt;', Result, i + 1);
              Inc(i, 4);
            end
            else if Result[i] = '>' then
            begin
              Result[i] := '&';
              Insert('gt;', Result, i + 1);
              Inc(i, 4);
            end
            else if Result[i] = '"' then
            begin
              Result[i] := '&';
              Insert('quot;', Result, i + 1);
              Inc(i, 6);
            end
            else if Result[i] = '&' then
            begin
              Insert('amp;', Result, i + 1);
              Inc(i, 5);
            end
            else
              Inc(i);
          end;
        end;
        

        【讨论】:

          【解决方案9】:

          在delphi中你有这个功能

          THTMLEncoding.HTML.Encode
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-14
            • 1970-01-01
            • 2023-03-22
            • 2023-03-27
            • 2014-05-09
            • 1970-01-01
            相关资源
            最近更新 更多