¿Existe una función estándar de Delphi para escapar de HTML?

6 minutos de lectura

Tengo un informe que se supone que debe tomar un control de cuadrícula y producir una salida HTML. Una de las columnas de la cuadrícula puede mostrar cualquiera de una serie de valores, o <Any>. Cuando esto se envía a HTML, por supuesto, termina en blanco.

Probablemente podría escribir alguna rutina para usar StringReplace para convertir eso en &lt;Any&gt; entonces mostraría este caso en particular correctamente, pero imagino que probablemente haya uno en el RTL en algún lugar que ya haya sido probado y lo haga bien. ¿Alguien sabe dónde podría encontrarlo?

  • Una forma Delphi de escapar del HTML… ¡Intraweb! 😉

    – LachlanG

    4 de junio de 2010 a las 4:07

Avatar de usuario de Andreas Rejbrand
andreas rejbrand

Estoy 99 % seguro de que tal función no existe en RTL (a partir de Delphi 2009). Por supuesto, sin embargo, es trivial escribir tal función.

Actualizar

HTTPUtil.HTMLEscape es lo que estás buscando:

function HTMLEscape(const Str: string): string;

No me atrevo a publicar el código aquí (probablemente una violación de los derechos de autor), pero la rutina es muy simple. Codifica ““, “&” y “”” para &lt;, &gt;, &amp;y &quot;. También reemplaza los caracteres #92, #160..#255 a códigos decimales, por ejemplo &#92;.

Este último paso no es necesario si el archivo es UTF-8, y también es ilógico, porque los caracteres especiales superiores, como ∮, se dejan como están, mientras que los caracteres especiales inferiores, como ×, están codificados.

Actualización 2

En respuesta a la respuesta de Stijn Sanders, realicé una prueba de rendimiento simple.

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.

la salida es

532031
801969

avatar de usuario de da-soft
da-suave

Parece que aquí hay un pequeño concurso 🙂 Aquí hay una implementación más:

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;

Actualización 1: se actualizó el código incorrecto proporcionado inicialmente.

Actualización 2: Y los tiempos:

HTMLEncode :   2286508597
HTMLEncode2:   3577001647
HTMLEncode3:    361039770

  • ¡Esta es una muy buena solución! (¡Quizás un poco exagerado, sin embargo! :)) La ganancia principal probablemente no sea el movimiento, sino el hecho de que no necesita asignar constantemente más espacio para el resultado. ¡Le daría un +1 a menos que fuera por el hecho de que no es una respuesta a la pregunta real! 🙂

    – Andreas Rejbrand

    4 de junio de 2010 a las 11:55


  • Bueno, te doy +1 solo porque es un hermoso ejemplo de optimización.

    – Andreas Rejbrand

    04/06/2010 a las 13:00

  • (Por cierto: ¿sabes que hay una sutil diferencia entre un “contenido” y un “concurso”? :))

    – Andreas Rejbrand

    4 de junio de 2010 a las 13:26

  • Seguro ! Tengo un problema similar con “conocer” y “carne” 🙂

    – da-suave

    4 de junio de 2010 a las 15:05

  • Gracias por esa rutina realmente rápida: tengo que convertir datos masivos, esto me salva el día.

    – Micha Schumann

    15 de junio de 2020 a las 17:32

Usualmente solo uso este código:

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;

(¿derechos de autor? es fuente abierta)

  • esto se ve mucho más lento que un ciclo simple: for i := 1 to length(Data) do case ord(Data[i]) de …

    – Andreas Rejbrand

    3 de junio de 2010 a las 19:06

  • Acabo de probar esto: Nested StringReplace: 801259 ticks. Un solo bucle: 532037 tics.

    – Andreas Rejbrand

    3 de junio de 2010 a las 19:14


  • hmm, interesante, ¿todavía podría haber algo de rendimiento al usar TStringStream?

    – Stijn Sanders

    4 de junio de 2010 a las 9:19

  • El principal ladrón de rendimiento es probablemente la reasignación constante de la cadena resultante. Esto se puede resolver como en la respuesta de da-soft. Pero el rendimiento no es un problema en absoluto para el OP, por lo que es más una nota al margen interesante. 🙂

    – Andreas Rejbrand

    4 de junio de 2010 a las 12:37

  • De todos modos, mil gracias por la entrada aquí, revisé mi HTMLEncode: xxm.svn.sourceforge.net/viewvc/xxm/trunk/Delphi/public/…

    – Stijn Sanders

    4 de junio de 2010 a las 21:13

Unit HTTPApp tiene una función llamada HTMLEncode. También tiene otras funciones relacionadas con HTML/HTTP.

No sé en qué versión de Delphi se introdujo, pero está el System.NetEncoding unidad que tiene:

TNetEncoding.HTML.Encode
TNetEncoding.HTML.Decode

funciones Leer aquí. Ya no necesitas bibliotecas externas para eso.

Avatar de usuario de Giordano Giaccaglia
Giordano Giaccaglia

Desde la unidad Soap.HTTPUtil o simplemente HTTPUtil para versiones anteriores de Delphi, puede usar

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;

avatar de usuario de rihar
rihar

qué tal esa forma de reemplazar caracteres especiales:

    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;

  • La función estándar se pregunta específicamente en esta pregunta, por lo que su respuesta no la responde, independientemente de si es correcta o no.

    – lukelazarovic

    9 sep 2015 a las 13:34

¿Ha sido útil esta solución?