Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Alguien sabe un modo mas efectivo de hacer esto con el texto de un memo (https://www.clubdelphi.com/foros/showthread.php?t=65353)

cocute 08-12-2009 15:39:08

Alguien sabe un modo mas efectivo de hacer esto con el texto de un memo
 
Lo que hago es cargar un fichero de texto de unas 700 lineas en un memo y me interesa quitale lineas por arriba y por abajo y luego reemplazar alguna palabra. Pero la eficiencia es nula y le cuesta bastante hacerlo.
Me podeis decir cual seria la forma correcta de hacerlo para que vaya rápido.
Quizas usando otro componente que no sea el memo clásico?

Cita:

//busco en el memo desde el principio una linea que coincida con PALABRA y borro todas las anteriores lineas
while Memo1.Lines[0]<>'PALABRA' do memo1.Lines.Delete(0);

//borrar todas las lineas del memo a partir de la 127 en adelante.
for I := 0 to Memo1.Lines.Count do memo1.Lines.Delete(127);

//recorrer las lineas que quedan y sustituir Palabra1 por Palabra2
for x := 0 to Memo1.Lines.Count do
memo1.lines[x]:= StringReplace( memo1.Lines[x],'palabra1','palabra2',[rfReplaceAll]);

gracias

DarkMan 08-12-2009 16:36:00

Tal vez trabajando con su propiedad text ganes eficiencia, aunque el mecanismo empleado será distinto.

cocute 08-12-2009 16:55:16

¿no existe algun modo de borrar lineas por un rango sin tener que recorrer una por una?
por ejemplo decir borrar desde la linea 0 a la 300.

mamcx 09-12-2009 01:37:44

Pienso que lo mejor seria usar Expresiones Regulares y pasar el texto a una vble de memoria, procesarla y luego pasarla al memo (asi no interfiere el código interno del memo reaccionando a los cambios del texto).

Ahora no veo que 700 lineas sea algo impresionante y no aclaras que es "ineficiente". Seria bueno empezar por ahi... que es "ineficiente"?

Delphi es super rapido con los strings, y he procesado al menos varias megas de texto sin lios...

Neftali [Germán.Estévez] 09-12-2009 10:16:19

Lo primero que se me ocurre es que trabajes con una estructura en memoria, no ligada a ningun componente. Eso te evitará operaciones de refresco y similares.

Código Delphi [-]
var
  TS:TStrings;
begin
  TS := TStringList.Create();

   // Asignar a TS lo que te interesa 
   ...
   // Trabajar en TS
   ...

  
  // Volver el resultado al memo.
  Memo.Lines.Clear;
  Memo.Lines.AddStrings(TS);

Otra cosa que te podría optimizar la operación, es no eliminar lo que te sobra, sino quedarte con lo que te vale y trabajar con eso.

1) Recorre las líneas hasta encontrar <PALABRA>
2) Copia desde esa línea hasta la 127 a TS
3) Trabaja sobre TS

cocute 09-12-2009 13:09:20

1 Archivos Adjunto(s)
Cita:

Empezado por mamcx (Mensaje 348457)

Ahora no veo que 700 lineas sea algo impresionante y no aclaras que es "ineficiente". Seria bueno empezar por ahi... que es "ineficiente"?

Delphi es super rapido con los strings, y he procesado al menos varias megas de texto sin lios...

no me quejo por quejarme, a la aplicacion le cuesta unos 7 segundos hacer todo el proceso. Y tengo un Intel Quad Q6600 y 4gb der ram, osea que no es problema de potencia.

Aclaro algo que no habia dicho, es que el texto es el código de una web que cargo previamente con el componente TIdHTTP de las Indy. Pero ese proceso es rápido.

Os pongo el codigo fuente para que lo veais, es un simple capricho de cargar solo el cuadro del tiempo de mi provincia desde la web de aemet.
Uso el webbrowser de http://www.bsalsa.com/, ya que me permite sin hacer nada cargar un string en el browser, ocultar scrollbars...

Seguramente el problema como decis esta en usar un tmemo para hacer los cambios, estoy probando trabajar directamente con el tstrings pero me faltan cosas que con el memo las hacia más facil.

He leido que quizas usando el componente JvHtmlParser de JEDI me iria mejor, pero lo he mirado y no me aclaro bien como funciona.

Delfino 09-12-2009 13:14:39

Cita:

Lo primero que se me ocurre es que trabajes con una estructura en memoria,
Pero si la propiedad Lines del memo es de tipo TStrings, para evitar operaciones visuales basta con llamar a los metodos BeginUpdate y EnUpdate..

cocute 09-12-2009 13:40:07

Cita:

Empezado por Delfino (Mensaje 348492)
Pero si la propiedad Lines del memo es de tipo TStrings, para evitar operaciones visuales basta con llamar a los metodos BeginUpdate y EnUpdate..

he añadido

Memo1.Lines.beginupdate;
...
....
...
Memo1.Lines.EndUpdate;

Pero creo que no se gana nada, sigue tardando bastante en procesar.

Neftali [Germán.Estévez] 09-12-2009 13:58:53

Si cambias tu código por uno como este:

Código Delphi [-]
procedure TForm1.FormActivate(Sender: TObject);
const
  CHAR_CRLF = #13#10;
var
  x:integer;
  Str:String;
begin
  Str := '';
Str := Str + '1-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF;
//cargo la web en un memo
memo1.Lines.Text:=idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22001');
  Str := Str + '2-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF;
//borro todas lineas hasta ...
while Memo1.Lines[0]<>'

' do memo1.Lines.Delete(0); Str := Str + '3-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF; //borro lineas de detras de ... while memo1.Lines[memo1.Lines.Count-1]<>'
' do memo1.Lines.Delete(memo1.Lines.Count-1); memo1.Lines.Delete(memo1.Lines.Count-1); memo1.Lines.Delete(memo1.Lines.Count-1); Str := Str + '4-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF; // Añado hoja de estilos a la primera linea memo1.lines[0]:= '

'; Str := Str + '5-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF; //reparo los links para que se muestren las imagenes: for x := 0 to Memo1.Lines.Count do memo1.lines[x]:= StringReplace( memo1.Lines[x],'/imagenes/','http://www.aemet.es/imagenes/',[rfReplaceAll]); Str := Str + '6-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF; //cargo el resultado en el webbrowser wb1.LoadFromStrings(memo1.lines); Str := Str + '7-' + FormatDateTime('hh:mm:ss:zzz', now) + CHAR_CRLF; MessageDlg(Str, mtInformation, [mbOK], 0); end;


La ventana que aparece es la siguiente:




Como ves, el tiempo realmente se "pierde"en la petición de la página, y no en las operaciones sobre el memo, aunque supongo que si eliminas los borrados tal y como te he dicho algo ganarías...

cocute 09-12-2009 14:26:28

Me parece que no,

Haciendo alguna prueba el tiempo que de verdad se nota se pierde al reemplazar para reparar los enlaces

Alguna alternativa a esto?
StringReplace( memo1.Lines[xx],'/imagenes/','http://www.aemet.es/imagenes/',[rfReplaceAll]);

cocute 09-12-2009 14:40:48

Aunque sea en plan chapucero ya lo he solucionado, ahora es casi instantaneo, ya solo falta limpiar todo lo que sobra, creo que se podrian quitar los memos, (pero no se como trabajar por lineas en un string):
El problema estaba en usar un memo linea por linea en el StringReplace en vez de usar el memo.Lines.text, usando un String como ya habiais dicho muchos la carga es practicamente instantanea.

Código PHP:

var ind,tt:integer;
begin
//cargo la web en un memo
memo1.Lines.Text:=idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22001');
 
 for 
ind := 0 to Memo1.Lines.count do
   
begin
    
if Memo1.Lines[ind]='<h2 class="titulo">' then
        begin
           
for tt := ind to Memo1.Lines.count do
            
begin
             memo2
.Lines.Add(Memo1.Lines[tt]);
              if 
Memo1.Lines[tt]=' <form name="frmMunicipio" method="get" action="/es/eltiempo/prediccion/localidades">' then
                begin
                 memo2
.lines[0]:= '<link rel="stylesheet" type="text/css" media="screen"  href="http://www.aemet.es/css/estilos.css" /><h2 class="titulo">';
                 
memo2.Lines.text:= StringReplacememo2.Lines.text,'/imagenes/','http://www.aemet.es/imagenes/',[rfReplaceAll]);
                 
wb1.LoadFromStrings(Memo2.lines);
                 exit
                
end;
            
end;
         
end;
      
end;
 
end


cocute 09-12-2009 15:36:47

He probado a quitar los memos y poner 2 tstringlist pero no me funciona, no hace nada, tambien he probado con Tstrings pero me da "error abtracto" o algo asi.
Que puede fallar? el mismo código con memos funciona.


Código PHP:

procedure TForm1.FormActivate(SenderTObject);
var 
ind,tt:integer;
    
file1,file2:TStringlist;
begin
file1
:= TStringlist.create;
file2:= TStringlist.create;
file1.text:=idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22001');
 for 
ind := 0 to file1.Count-do
   
begin
    
if file1.ValueFromIndex[ind]='<h2 class="titulo">' then
        begin
           
for tt := ind to file1.Count-do
            
begin
             file2
.Add(file1.ValueFromIndex[tt]);
              if 
file1.ValueFromIndex[tt]=' <form name="frmMunicipio" method="get" action="/es/eltiempo/prediccion/localidades">' then
                begin
                 file2
.ValueFromIndex[0]:= '<link rel="stylesheet" type="text/css" media="screen"  href="http://www.aemet.es/css/estilos.css" /><h2 class="titulo">';
                 
file2.text:= StringReplacefile2.text,'/imagenes/','http://www.aemet.es/imagenes/',[rfReplaceAll]);
                 
wb1.LoadFromStrings(file2);
                 
file1.Free;
                 
file2.Free;
                 exit
                
end;
            
end;
         
end;
      
end
end


maeyanes 09-12-2009 15:43:39

Hola...

Cita:

Empezado por cocute (Mensaje 348502)
Aunque sea en plan chapucero ya lo he solucionado, ahora es casi instantaneo, ya solo falta limpiar todo lo que sobra, creo que se podrian quitar los memos, (pero no se como trabajar por lineas en un string):

Si ya trabajas con la propiedad Lines del TMemo, ya estás trabajando con un TStringList:

Código Delphi [-]
// Esto:
Memo1.Lines.Count
// Equivale a esto:
StringListVar.Count

// Esto:
Memo1.Lines[tt]
// Equivale a esto:
StringListVar[tt]

Como verás en los ejemplos anteriores, es lo mismo...


Saludos...

maeyanes 09-12-2009 16:03:22

Hola...

Cita:

Empezado por cocute (Mensaje 348506)
He probado a quitar los memos y poner 2 tstringlist pero no me funciona, no hace nada, tambien he probado con Tstrings pero me da "error abtracto" o algo asi.
Que puede fallar? el mismo código con memos funciona.


Código PHP:

procedure TForm1.FormActivate(SenderTObject);
var 
ind,tt:integer;
    
file1,file2:TStringlist;
begin
file1
:= TStringlist.create;
file2:= TStringlist.create;
file1.text:=idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22080');
 for 
ind := 0 to file1.Count-do
   
begin
    
if file1.ValueFromIndex[ind]='<h2 class="titulo">' then
        begin
           
for tt := ind to file1.Count-do
            
begin
             file2
.Add(file1.ValueFromIndex[tt]);
              if 
file1.ValueFromIndex[tt]=' <form name="frmMunicipio" method="get" action="/es/eltiempo/prediccion/localidades">' then
                begin
                 file2
.ValueFromIndex[0]:= '<link rel="stylesheet" type="text/css" media="screen"  href="http://www.aemet.es/css/estilos.css" /><h2 class="titulo">';
                 
file2.text:= StringReplacefile2.text,'/imagenes/','http://www.aemet.es/imagenes/',[rfReplaceAll]);
                 
wb1.LoadFromStrings(file2);
                 
file1.Free;
                 
file2.Free;
                 exit
                
end;
            
end;
         
end;
      
end
end


Checando este código con el que pusiste usando el TMemo, veo que es muy diferente. Aquí una versión usando TStringList:

Código Delphi [-]
var
  Web: TStringList;
  Temp: TStringList;
  ind: Integer;
  tt: Integer;

begin
  Web := TStringList.Create;
  Temp := TStringList.Create;
  try
    //cargo la web en un TStringList
    Web.Text := idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22001');
    for ind := 0 to Pred(Web.Count) do
      if Web[ind] = '< h2 class="titulo" >' then
        for tt := ind to Pred(Web.Count) do
        begin
          Temp.Add(Web[tt]);
          if Web[tt] = ' < form name="frmMunicipio" method="get" ' +
            'action="/es/eltiempo/prediccion/localidades" >' then
          begin
            Temp[0] := '< link rel="stylesheet" type="text/css" media="screen" ' + 
              'href="http://www.aemet.es/css/estilos.css" / >< h2 class="titulo" >';
            Temp.Text := StringReplace(Temp.Text, '/imagenes/', 
              'http://www.aemet.es/imagenes/', [rfReplaceAll]);
            wb1.LoadFromStrings(Temp);
            Exit
          end
        end
  finally
    Web.Free;
    Temp.Free
  end
end;


Saludos...

P.D. TString es una clase abstracta y es por eso que cuando quieres instanciar un objeto de esa clase obtienes el error "abstracto"

Neftali [Germán.Estévez] 09-12-2009 16:17:17

Cita:

Empezado por cocute (Mensaje 348506)
He probado a quitar los memos y poner 2 tstringlist pero no me funciona, no hace nada, tambien he probado con Tstrings pero me da "error abtracto" o algo asi.
Que puede fallar? el mismo código con memos funciona.

Si a tí te va bien con los 2 memos (a mi no me funciona) puedes dejarlo así y en todo caso utilizar BeginUpdate y EndUpdate para eliminar los retardos de pintado.

Utilizar TStrings/TStringList no te aportará más velocidad, ya que las propias Lines del componente Memo ya son TStrings, simplemente era para que no tuvieras que utilizar TMemos sin ser necesario.

El primer código utilizando TStrings sería así:

Código PHP:

procedure TForm1.FormActivate(SenderTObject);
var
  
x:integer;
  
TS:TStrings;
begin

  TS 
:= TStringList.Create();
  try
    
TS.Text :=idHttp1.Get('http://www.aemet.es/es/eltiempo/prediccion/localidades?l=22001');

    while 
TS[0]<>'<h2 class="titulo">' do begin
      TS
.Delete(0);
    
end;

    while 
TS[TS.Count-1]<>'  <form name="frmMunicipio" method="get" action="/es/eltiempo/prediccion/localidades">' do begin
      TS
.Delete(TS.Count-1);
    
end;

    
TS.Delete(TS.Count-1);
    
TS.Delete(TS.Count-1);

    
TS[0]:= '<link rel="stylesheet" type="text/css" media="screen"  href="http://www.aemet.es/css/estilos.css" /><h2 class="titulo">';

    
TS.Text := StringReplace(TS.Text,
      
'/imagenes/',
      
'http://www.aemet.es/imagenes/',[rfReplaceAll]);

    
wb1.LoadFromStrings(TS);
  
finally
    FreeAndNil
(TS);
   
end;
end

El error abstracto suele dar cuando utilizas como constructor:

Código Delphi [-]
var
  TS:TStrings
begin
  TS := TStrings.Create();

En lugar de esto, ya que TStrings es una clase abstracta.

Código Delphi [-]
var
  TS:TStrings
begin
  TS := TStringList.Create()

cocute 09-12-2009 16:26:06

pues ninguno de los dos ejemplos que me poneis funcionan, ni el mio con Tstrings tampoco. (aunque deberian)
Será por la version de Delphi que es la 2010¿?

con los memos si funciona.

Neftali [Germán.Estévez] 09-12-2009 16:33:15

El último que he puesto yo está compilado con Delphi 2009.

cocute 09-12-2009 17:15:53

pues me esta pasando una cosa muy rara ya que lo que antes me funcionaba ahora no, voy a probar con el delphi 2009 que tengo en otra particion.

cocute 09-12-2009 17:34:47

Neftali, el que me pones tu compila pero al abrirlo me da error:
List index of bounds (-1), pero me da que aun solucionando eso no funcionara como los otros.

El de maeyanes le pasa lo que al mio con Tstrings compila bien pero no muestra nada.

No se porque solo hay manera de que me funcione el que va con 2 Memos.


He probado a compilar en Delphi 2009 y delphi 2006 y siguen sin funcionar con Tstringlist


Por cierto el enlace base ha variado, no se si por tanto probar lo han cambiado, bueno han cambiado de todas ciudades, por si probais de nuevo cambiadlo a:
http://www.aemet.es/es/eltiempo/pred...s/huesca-22001
o a la ciudad que sea

cocute 09-12-2009 19:45:28

por cierto, aparte veo que el componente EmbeddedWB tiene una opcion para meterle una hoja de estilos (HOSTCSS) sin tener que cargarla via web.
Asi que aun se gana más en velociodad, ya que la hoja de estilos es mas pesada que la web en si.
Aunque seria conveniente dejar solo lo que se emplea del fichero.


La franja horaria es GMT +2. Ahora son las 08:45:51.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi