Seguimos avanzando en la serie…

Como os comentaba en la parte segunda, existía un pequeño problema, que mientras se corrige y no se corrige, nosotros podemos salvar de formas distintas. Vamos a buscar la mas sencilla para este caso concreto.

Veamos..

En nuestro caso, vamos a eliminar el boton [Seguir] dejando en una sola acción el recorrido de la búsqueda, de forma que la instancia no se sale de ambito hasta que llega al final del método, momento en el que son liberados los recursos asociados a la instancia creada de TRegEx. Eso lo podéis comprobar de una forma muy sencilla poniendo un punto de parada y comprobando que efectivamente es destruida la instancia de TPerlRegEx que es la clase que en ultima instancia liberará la memoria del proceso.

Este tipo de errores son bastante dificiles de detectar en un ambiente de trabajo normal (me refiero a fuera de lo que puede ser un ejemplo de pocas lineas) pues no siempre tienen que generar excepciones inmediatas y suelen ofuscarse entre las lineas del entorno inmediato que la rodean.

Así pues… eliminamos la acción asociada a Seguir y el componente TBitBtn que la disparaba. Tampoco nos hará falta la variable FSeguir ni los update de las acciones. Y seguidamente hacemos unos pequeños cambios en el cuerpo del procedimiento vinculado a la accion acIniciar. Nos basta alojar un el bucle que recorra las coincidencias y dejarle al usuario la opción de seguir o no. Esto último nos ha hecho valorar que lo que era un procedimiento, que habíamos llamado EvaluarResultado( ) ahora sea una función y devuelva el deseo de seguir adelante o no de nuestro usuario.

Estas son las lineas que hemos modificado:

procedure TBusquedasConExpRegulares.acIniciarExecute(Sender: TObject);
var
  pre: TRegEx;
begin
   //vaciamos la lista de resultados
   lbxResultados.Items.Clear;
   //inciamos la creación personalizada de la expresión regular
   pre:= CrearExpresionRegular;
   // obteniendo la colección de resultados tras ejecutar la expresión
   CollOfMatch:= pre.Matches(rchContenedorTexto.Text);
   //nos valemos de un enumerador para recorrer la estructura
   EnumCollOfMatch:= CollOfMatch.GetEnumerator;
   //evaluamos el resultado de la busqueda
   while EnumCollOfMatch.MoveNext and EvaluarResultado do;
end;
function TBusquedasConExpRegulares.EvaluarResultado: Boolean;
begin
   with EnumCollOfMatch.Current do
   begin
    //añadimos la subcadena encontrada
    lbxResultados.Items.Add('La palabra ' +
                            Value + ' ' +
                            'ha sido encontrado en la posición ' +
                            IntToStr(Index-1)
                            );
    rchContenedorTexto.SelStart:= Index-1;  //Su posición en el texto inicial
    rchContenedorTexto.SelLength:= Length;  //Su longitud
    TextoBarraEstado(Length, Index-1);      //Y lo mostramos además en la barra
   end;                                     //de estado
   Result:= MessageDlg('Coincidencia encontrada...', mtWarning, [mbYes, mbNo], 0, mbYes) = mrYes;
end;

Entonces quedaría de la siguiente forma ya con los cambios que hemos hecho:

cambios

unit UBusquedasConExpRegulares;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, CheckLst, ComCtrls, ActnList, RegularExpressions;
type
  TBusquedasConExpRegulares = class(TForm)
    edCadenaBusqueda: TEdit;
    bnIniciar: TButton;
    Label2: TLabel;
    Label1: TLabel;
    chlxOpciones: TCheckListBox;
    lbxResultados: TListBox;
    rchContenedorTexto: TRichEdit;
    Label3: TLabel;
    Label4: TLabel;
    Acciones: TActionList;
    acIniciar: TAction;
    sbBusqueda: TStatusBar;
    Button2: TButton;
    acReemplazar: TAction;
    Label5: TLabel;
    edCadenaAReemplazar: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure acIniciarExecute(Sender: TObject);
    procedure acReemplazarExecute(Sender: TObject);
  private
    { Private declarations }
    procedure TextoBarraEstado(ALength, AOffset: Integer);
    function EvaluarResultado: Boolean;
    function CrearExpresionRegular: TRegEx;
  public
    { Public declarations }
  end;
var
  BusquedasConExpRegulares: TBusquedasConExpRegulares;
  CollOfMatch: TMatchCollection;
  EnumCollOfMatch: TMatchCollectionEnumerator;
implementation
{$R *.dfm}
procedure TBusquedasConExpRegulares.acIniciarExecute(Sender: TObject);
var
  pre: TRegEx;
begin
   //vaciamos la lista de resultados
   lbxResultados.Items.Clear;
   //inciamos la creación personalizada de la expresión regular
   pre:= CrearExpresionRegular;
   // obteniendo la colección de resultados tras ejecutar la expresión
   CollOfMatch:= pre.Matches(rchContenedorTexto.Text);
   //nos valemos de un enumerador para recorrer la estructura
   EnumCollOfMatch:= CollOfMatch.GetEnumerator;
   //evaluamos el resultado de la busqueda
   while EnumCollOfMatch.MoveNext and EvaluarResultado do;
end;
procedure TBusquedasConExpRegulares.acReemplazarExecute(Sender: TObject);
var
  pre: TRegEx;
begin
  //vaciamos la lista de resultados
  lbxResultados.Items.Clear;
  //inciamos la creación personalizada de la expresión regular
  pre:= CrearExpresionRegular;
  //reemplazamos todas las coincidencias
  rchContenedorTexto.Text:= pre.Replace(rchContenedorTexto.Text,
                                        edCadenaAReemplazar.Text);
end;
function TBusquedasConExpRegulares.CrearExpresionRegular: TRegEx;
var
  i: Integer;
  fOp: TRegExOptions;
begin
   //vaciamos el conjunto de opciones para aplicar
   fOp:= [];    // y procedemos a obtener las validas
   for i := 0 to chlxOpciones.Count - 1 do
   begin
      if chlxOpciones.Checked[i] then
         case i of
           0: fOp:= fOp + [roIgnoreCase];
           1: fOp:= fOp + [roMultiLine];
           2: fOp:= fOp + [roSingleLine];
           3: fOp:= fOp + [roIgnorePatternSpace];
           4,5:;
           //4: fOp:= fOp + [preAnchored];
           //5: fOp:= fOp + [preUnGreedy];
           6: fOp:= fOp + [roExplicitCapture];
         end;
   end;
   // Creamos el registro para manejar la expresión regular
   Result:= TRegEx.Create(edCadenaBusqueda.Text, fOp);
end;
function TBusquedasConExpRegulares.EvaluarResultado: Boolean;
begin
   with EnumCollOfMatch.Current do
   begin
    //añadimos la subcadena encontrada
    lbxResultados.Items.Add('La palabra ' +
                            Value + ' ' +
                           'ha sido encontrado en la posición ' +
                           IntToStr(Index-1)
                           );
    rchContenedorTexto.SelStart:= Index-1;  //Su posición en el texto inicial
    rchContenedorTexto.SelLength:= Length;  //Su longitud
    TextoBarraEstado(Length, Index-1);      //Y lo mostramos en la barra
   end;                                           //de estado
   Result:= MessageDlg('Coincidencia encontrada...¿Seguir?',
                             mtWarning, [mbYes, mbNo], 0, mbYes) = mrYes;
end;
procedure TBusquedasConExpRegulares.FormCreate(Sender: TObject);
begin
  rchContenedorTexto.Lines.LoadFromFile('texto.txt', TEncoding.UTF8);
end;
procedure TBusquedasConExpRegulares.TextoBarraEstado(ALength, AOffSet: Integer);
begin
 with sbBusqueda do
 begin
   sbBusqueda.Panels[0].Text:= 'Length:'+ IntToStr(ALength);
   sbBusqueda.Panels[1].Text:= 'OffSet:'+ IntToStr(AOffSet);
 end;
end;
end.

Seguimos avanzando…

4 comentarios sobre “Expresiones regulares: Novedad en XE (Parte 3.1)

    1. Gracias Javier.
      Gracias Germán.

      Todos los comentarios se agradecen y por supuesto alientan y estimulan a seguir trabajando por nuestra Comunidad. Es más… Creo que lo peor que nos puede pasar es que todo este trabajo y horas dedicadas no generen ilusión y sea algo que nos deje indiferentes.
      🙂
      Subí ayer al servidor el último fragmento de la serie, que estaba por acabar. Por eso el retraso en este comentario.

      Un saludo,
      Salvador

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s