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 <Any>
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?
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 <
, >
, &
y "
. También reemplaza los caracteres #92, #160..#255 a códigos decimales, por ejemplo \
.
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 + '<';
'>': result := result + '>';
'&': result := result + '&';
'"': result := result + '"';
else
result := result + Data[i];
end;
end;
function HTMLEncode2(Data: string):string;
begin
Result:=
StringReplace(
StringReplace(
StringReplace(
StringReplace(
Data,
'&','&',[rfReplaceAll]),
'<','<',[rfReplaceAll]),
'>','>',[rfReplaceAll]),
'"','"',[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
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('<');
'>': Encode('>');
'&': Encode('&');
'"': Encode('"');
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,
'&','&',[rfReplaceAll]),
'<','<',[rfReplaceAll]),
'>','>',[rfReplaceAll]),
'"','"',[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.
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 + '<'; { Do not localize }
'>' : Result := Result + '>'; { Do not localize }
'&' : Result := Result + '&'; { Do not localize }
'"' : Result := Result + '"'; { 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;
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
Una forma Delphi de escapar del HTML… ¡Intraweb! 😉
– LachlanG
4 de junio de 2010 a las 4:07