• Delphi

 #413153  por WarZ0n3
 
Hace mucho que no hago nada en ASM y ya que hoy en la mañana tuve 2 horas libres y estaba aburrido, retome un pequeño manual de ASM que tenia y en 30 minutos me hice esto, demasiado simple pero muy útil en programación con sockets, espero les sirva.

Lo que hace esta función es extraer un string de otro string defectuoso, puede usarse por ejemplo, para guardar muchas listas defectuosas(en un TStringList claro esta) e ir limpiandolas.
Como explicaba esto es uno de los tantos usos que se le pueda dar.
Les dejo el código:
program ExtractMemString;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes;

{/*******************************************\}
{        ExtractMemString @Por WARZ0N3        }
{ Explicacion:                                }
{ Extrae una palabra de un string defectuoso, }
{ muy util en programacion con Sockets.       }
{ Pascal+ASM ejecuta el codigo mas optimo y   }
{ mucho mas rapido...                         }
{/*******************************************\}
{ Uso:                                        }
{ __ExtractMemString(                         }
{ 'Desde_char_a_remover', variable_defectuosa,}
{ 'Hasta_char_a_remover', Lista_strings);     }
{\*******************************************/}
{ Ejemplo:                                    }
{ __ExtractMemString('!', '&%[email protected]', '-', TStringList);}
{ devuelve: PALABRA                           }
{/*******************************************\}
function __ExtractMemString(from_s:Char; Param:pChar; to_s:Char; TsStrMem:TStringList):pChar;
var
  tos, fms:integer;
  lnStr:integer;

  StrMem:pchar;
  CpyStrMem:pchar;
  allocStrMem:pchar;
  lenStr:integer;
  Delim:integer;
  sPos:integer;
begin
  StrNew(@StrMem);
  StrMem:=Param; { palabra defectuosa }
  lenStr:=StrLen(pChar(StrMem));

  Delim:= LastDelimiter(from_s, StrMem); { desde }
  sPos:=Pos(to_s, StrMem); { hasta }
  asm
    @@startup:
      XOR EAX, EAX
      MOV EAX, sPos
      PUSH EAX
      POP tos
      DEC tos

      CMP EAX, 00000000h
      JZ @plSum
      JMP @pSum

      @plSum: ADD tos, EAX
      @pSum:
        XOR EBX, EBX
        MOV EBX, lenStr
        MOV lnStr, EBX

        XOR ECX, ECX
        MOV ECX, delim
        MOV fms, ECX
        SUB tos, ECX
  end;
  allocStrMem:=StrAlloc(lnStr);
  StrLCopy(allocStrMem, fms+StrMem, tos); //-$00000003
  TsStrMem.Add(allocStrMem);
  StrDispose(allocStrMem);
end;

var TsStrMem:TStringList;
begin
  TsStrMem:= TStringList.Create;
  {*** Llamada a la funcion ***}
  __ExtractMemString('!', '**-!PALABRA?**', '?', TsStrMem); { devuelve PALABRA }
  WriteLn(TsStrMem[0]);
  TsStrMem.Free;
  sleep(3500);
end.
 #413441  por joselin
 
sinceramente no entiendo , se usa como depuracion?
podrias dar un ejemplo de uso
o explicarmelo con manzanas
 #413442  por Pink
 
muy ofuscado escribió:sinceramente no entiendo , se usa como depuracion?
podrias dar un ejemplo de uso
o explicarmelo con manzanas

Se podría decir que es como un _StringBetween. osea sacar una string entre unos delimitadores datos.

saludos
 #413443  por Metal_Kingdom
 
Pensaba que me devolvería varios resultados si por ejemplo quiero filtrar esto:

**-!PALABRA?**--!Prueba?

debería dar como primer resultado 'PALABRA' y como segundo resultado 'Prueba', pero lo que hace es devolverme 'Prueba?' y tirar un error de esos feos.

@muy ofuscado:
Es como un split a doble delimitador (de 1 caracter), que según entiendo, la idea es que filtre todo el texto arrojando todos los splits en el stringlist.

Faltaría ver por qué falla con ejemplos como el que puse

El que yo hice es este:
{
Creado en delphi 7
Fecha: 12-01-2012
Autor: Metal_Kingdom
Web: udtools.net
Finalidad: "Separar" datos de cadenas (devuelve el contenido entre dos delimitadores).
Forma de uso: ej.:
Showmessage (sSplit ('putillas hola udtools.net adios lalalala' , 'hola ', ' adios')); //Devuelve "udtools.net"
}

Function sSplit(cadena, delimitador, delimitador2: string): String;
var
a: string;
contador1, contador2: integer;
begin
contador1:= pos(delimitador, cadena);
contador2:= pos(delimitador2, cadena);
Result:= copy(cadena,contador1 + length(delimitador), (contador2 - contador1) - length(delimitador));
end;
Y tiempo después, el que hizo mi amigo STX, que funciona como la idea de este hilo:
function cortar(xStr : String; dl , dl2: String) : TStrings;
var
a, b : Integer;
Splited : String;
begin
Result := Nil;
Result := TStringList.Create;
a := AnsiPos(dl, xStr);
while a <> 0 do
begin
a := AnsiPos(dl, xStr);
b := AnsiPos(dl2, xStr);
splited := Copy(xStr, a + Length(dl), b - a - Length(dl));
if Length(splited) <> 0 then
begin
Result.Add (splited);
xStr := Copy(xStr, b + Length(dl2), Length(xStr));
end;
end;
end;
Saludos.
 #413444  por Pink
 
@Metal_Kingdom
**-!PALABRA?**--!Prueba?

El resultado debería ser Prueba pero esta mal hecha la función

usa Lastdelimiter que señalaría **-!PALABRA?**--!Prueba? y pos para ? Cualquier que seria el primero **-!PALABRA?**--!Prueba? por eso no funciona.


A demas el codigo ASM puede hacer mucho mejor seria cuestión de un bucle while.


saludos
 #413445  por Metal_Kingdom
 
Exacto Pink..

Aunque si hubiera usado LastDelimiter en (to_s, StrMem) hubiera fallado igual ya que la cadena sigue intacta y siempre llevará al último delimitador (de ahí su nombre), y nunca podrá mostrar el siguiente split (WriteLn(TsStrMem[1]);)

Yo no habría usado lastdelimiter sino POS, y una vez llegado al pimer split eliminaría los 2 separadores para continuar con el siguiente split.
 #413446  por Metal_Kingdom
 
//no me deja editar..
//con unos ejemplos de cómo se arreglaría esto:

Tenemos por ejemplo esta cadena: **-!parte1?**--!parte2?--!parte3?

Si usamos LastDelimiter en vez de POS, lo que conseguimos es arrojar los resultados a la inversa, es decir:

1er split: parte3
2º split: parte2
3er split: parte1

Para lograrlo necesita eliminar cada split generado jundo a sus delimitadores antes del siguiente split, o bien sumar posiciones a medida que el split avanza.

Lastdelimiter se centrará siempre en lo último, por tanto se debe hacer lo siguiente, por ejemplo:
**-!parte1?**--!parte2?--!parte3? //primera pasada, lastdelimiter irá a parar ahí.
Entonces resultado del split: parte3, lo agregamos al stringlist.

Antes de continuar, eliminamos el split ya añadido, para que lastdelimiter se centre en la nueva pasada, siendo:
**-!parte1?**--!parte2?-- //ahora lastdelimiter irá aquí, obtenemos el split, lo añadimos al stringlist y eliminamos.
Resultado del split: parte2

Eliminamos y ya solo nos queda:
**-!parte1?**-- //igual que antes, extraemos el split y lo añadimos al stringlist, y eliminamos

Si tamaño de cadena = 0 ó ambas posiciones de lastdelimiter = 0 entonces nos salimos.

Entonces en el stringlist ya tendríamos los datos y sin errores, un split por cada línea del stringlist:

parte3
parte2
parte1

Si en vez de hacer uso de lastdelimiter usaramos Pos, el órden sería:

parte1
parte2
parte3

///////////////////////////////////

Tras la explicación del cómo lo haría yo, sospecho que StrLCopy algo tiene que ver con el asunto del error, ya sean los caracteres a copiar, la falta de un bucle, etc...

Un saludo.
 #413447  por joselin
 
gracias metal , pink mejoro mi perspectiva
ahora recuerdo que use un split para un programa que publico fakedoor



saludos
 #413454  por WarZ0n3
 
No estuve en estos días y la verdad que recién viendo los comentarios me encuentro mala dicha...
Tratare de responderles a todos de la manera mas explicita posible, ya que me es difícil deducir si es como una agresión o una critica...
me gustaría que me respondieran

Sobre la función:
No la copie de ningún usuario ni tampoco "esta mal echa" que no la sepa usar no es mi problema, ami me funciono perfectamente de manera "estándar" tanto como con sockets...
Si no fui lo suficiente explicito me tratare de explicar....

Esta función devuelve una string(especifico) de un string defectuoso en este caso **-!PALABRA?**--!Prueba? le esta lanzando un error o problema, por que si quiere obtener el resultado "Prueba" no debe repetir, esta es una función para palabras tan largas como usted quiera (pero sin repetir caracteres), y en repetición como podría ser un bucle

EJ: **-!PALABRA?**--#[email protected]
__ExtractMemString('#', '**-!PALABRA?**--#[email protected]', '@', TsStrMem);
esto devolvería :> Prueba (sin ningún problema)

claro que deben ser caracteres, y podrían estar dentro de otro bucle... insisto, yo lo use con sockets(pasando parametros), y no tuve ningún problema.

PD: Si hay algún otro problema podría probar quitando "StrDispose" o tan solo comentándolo.
respeto por el trabajo ajeno, gracias.
 #413458  por Pink
 
En ningún momento se esta menospreciando ni ofendiendo tu aporte.
Todas son criticas constructivas. y desconociendo sobre la aplicación que usted le da.
saludos

esto esta de mas.
respeto por el trabajo ajeno, gracias
 #413459  por WarZ0n3
 
Pink escribió:En ningún momento se esta menospreciando ni ofendiendo tu aporte.
Todas son criticas constructivas. y desconociendo sobre la aplicación que usted le da.
saludos

esto esta de mas.
respeto por el trabajo ajeno, gracias
Entonces fue un muy mal entendido de mi parte, me disculpo.
Retomando el tema de la función... pude ver un pequeño error, y sí esta a la vista, use lastDelimiter esto sucede cuando uno saca las cosas antes de tiempo, lo sucedido fue que había usado Pos en un principio pero para cuestiones de prueba lo cambie por lastDelimiter, si no me cree usted también puede apreciar que use CpyStrMem y en ningún momento hago el llamado, un gran error de mi parte.
Bueno aquí la corrección del código, me gusta aclarar las cosas respetuosamente, si alguien tiene otro problema notifíquelo yo me ocupare de ello, en todo caso abriré otro post para quede dicho.

Arreglada y ahora funciona correctamente(O por lo menos ami, en el ejemplo se ve claramente).

Nota: Esta funcion tambien tiene como objetivo alojar aquellos strings en el heap y en la memoria usando ASM. Para hacerlo de una manera distinta a la habitual se ha usado StrLCopy, StrNew, etc... en referencia a las rtl. Usted puede encontrar documentación en freepascal.org

Imagen

Sin más:
program ExtractMemString;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes,
  Windows;

{/*******************************************\}
{        ExtractMemString @Por WARZ0N3        }
{ Explicacion:                                }
{ Extrae una palabra de un string defectuoso, }
{ muy util en programacion con Sockets.       }
{ Pascal+ASM ejecuta el codigo mas optimo y   }
{ mucho mas rapido...                         }
{ Esta funcion tambien tiene como objetivo    }
{ alojar aquellos strings en el heap y en la  }
{ memoria usando ASM.                         }
{ Para hacerlo de una manera distinta a la    }
{ habitual se ha usado StrLCopy,StrNew, etc.. }
{ en referencia a las rtl usted puede         }
{ encontrar documentación en freepascal.org   }
{/*******************************************\}
{ Uso:                                        }
{ __ExtractMemString(                         }
{ 'Desde_char_a_remover', variable_defectuosa,}
{ 'Hasta_char_a_remover', Lista_strings);     }
{\*******************************************/}
{ Ejemplo:                                    }
{ __ExtractMemString('!', '&%[email protected]', '-', TStringList);}
{ devuelve: PALABRA                           }
{/*******************************************\}
function __ExtractMemString(from_s:Char; Param:pchar; to_s:Char; TsStrMem:TStringList):pChar;
var
  tos, fms:integer;
  lnStr:integer;

  StrMem:pchar;
  allocStrMem:pchar;
  lenStr:integer;
  Delim:integer;
  sPos:integer;
begin
  StrNew(@StrMem);
  StrMem:=Param; { palabra defectuosa }
  lenStr:=StrLen(pChar(StrMem));

  //Delim:= LastDelimiter(from_s, StrMem); { desde }
  Delim:= Pos(from_s, StrMem);
  sPos:=Pos(to_s, StrMem); { hasta }
  asm
    @@startup:
      XOR EAX, EAX
      MOV EAX, sPos
      PUSH EAX
      POP tos
      DEC tos

      CMP EAX, 00000000h
      JZ @plSum
      JMP @pSum

      @plSum: ADD tos, EAX
      @pSum:
        XOR EBX, EBX
        MOV EBX, lenStr
        MOV lnStr, EBX

        XOR ECX, ECX
        MOV ECX, delim
        MOV fms, ECX
        SUB tos, ECX
  end;
  allocStrMem:=StrAlloc(lnStr);
  StrLCopy(allocStrMem, fms+StrMem, tos); //-$00000003
  TsStrMem.Add(allocStrMem);

  StrDispose(allocStrMem);
end;

var
  TsStrMem:TStringList;
  i:integer;
  palabras_defectuosas:array[0..MAX_PATH] of string;

  palabra_defectuosa_simple:string;
  otra_palabra_defectuosa:string;
begin
  TsStrMem:= TStringList.Create;
  {** EJEMPLO ARRAY DE PALABRAS DEFECTUOSAS **}
  // fijese como por más que se repitan palabras defectuosas los caracteres
  // a delimitar seran siempore '$' y '&' (a modo de ejemplo pero podria ser cualquiera)
  palabras_defectuosas[0]:='·%"$PRUEBA&/%[email protected]';
  palabras_defectuosas[1]:='·---$PRUEBA&·"@';
  palabras_defectuosas[2]:='(%#$PRUEBA&/4968';
  palabras_defectuosas[3]:=')/$PRUEBA&/***';
  palabras_defectuosas[4]:='!!---+"$PRUEBA&/+==';
  // ... tantas palabras_defectuosas como queramos
  { Array defectuoso }
  for i:=0 to length(palabras_defectuosas)-1 do begin
    if palabras_defectuosas[i]>#0 then
      WriteLn('Arrays defectuosos: '+palabras_defectuosas[i]);
  end;

  //***********************************************************
  { Aquí como ejemplo se usa un llamado al array limpiandolo }
  for i:=0 to length(palabras_defectuosas)-1 do begin
    if palabras_defectuosas[i]>#0 then begin

    { Llamado de la función }
      __ExtractMemString('$', pChar(palabras_defectuosas[i]), '&', TsStrMem);
      WriteLn('Array limpio: '+TsStrMem[i]);

    end;
  end;
  //***********************************************************

  writeLn(sLineBreak); // salto de linea

  { Si usted lo prefiere usar en singular }
  { En este caso usaremos como ejemplo los limitadores "/" y "\" }
  palabra_defectuosa_simple:='(%#@@@__.r$/PRUEBA\&49&---?????68####';
  __ExtractMemString('/', pchar(palabra_defectuosa_simple), '\', TsStrMem);
  writeLn('Palabra simple defectuosa: '+palabra_defectuosa_simple);
  writeLn('Palabra simple limpia: '+TsStrMem[5]);
  //***********************************************************

  writeLn(sLineBreak); // salto de linea

  { De otro modo }
  TsStrMem.Clear; // Si usted desea limpiar para volver empezar desde el primer parametro
  otra_palabra_defectuosa:= '$%&/()=^PRUEBA_!"·$%$';
  __ExtractMemString('^', pchar(otra_palabra_defectuosa), '_', TsStrMem);
  writeLn('Otra palabra defectuosa... : '+otra_palabra_defectuosa);
  writeLn('Otra palabra limpia... : '+TsStrMem[0]);

  {/*************************************************\}
  {
    Notese que en el primer array defectuoso usamos
    como de limitador '$' y '&'

    En el segundo ejemplo (el de la palabra simple)
    usamos '/' y '\'

    Y en el tercer ejemplo como delimitador '^' y '_'

    Como resultado obtenemos : PRUEBA
  }
  {\*************************************************/}

  TsStrMem.Free;
  sleep(8500);
end.
 #413468  por Metal_Kingdom
 
Claro que no se trataba de una ofensa amigo, ni por asomo, hiciste un buen trabajo, quizás faltó indicar en el hilo el detalle de que no se pueden repetir los caracteres usados como delimitadores.

Cuando tenga tiempo pruebo la actualización, buen trabajo compañero
 #413477  por Pink
 
Funciona Perfecto... me descargue el Delphi para probarlo

@WarZ0n3 también se podría hacer algo similar sacando siempre caracteres alfanuméricos. [a-zA-Z0-9]

Aquí dejo mmm digamos unas correcciones.

allocStrMem:=StrAlloc(lnStr); reservas mas memoria de la necesaria para tu cadena
resultante que seria Prueba 6 y reservas 15.
//Entonces podría ser así.
allocStrMem:=StrAlloc(sPos-Delim-1)
StrLCopy(allocStrMem, Delim+StrMem, sPos-Delim-1); //-$00000003
TsStrMem.Add(allocStrMem);
Y quedaría así y mas rapido porque nos ahorramos el ASM.
function __ExtractMemString(from_s:Char; Param:pchar; to_s:Char; TsStrMem:TStringList):pChar;
var
  tos, fms:integer;
  lnStr:integer;

  StrMem:pchar;
  allocStrMem:pchar;
  lenStr:integer;
  Delim:integer;
  sPos:integer;
begin
  StrNew(@StrMem);
  StrMem:=Param; { palabra defectuosa }
  lenStr:=StrLen(pChar(StrMem));

  //Delim:= LastDelimiter(from_s, StrMem); { desde }
  Delim:= Pos(from_s, StrMem);
  sPos:=Pos(to_s, StrMem); { hasta }
  allocStrMem:=StrAlloc(sPos-Delim);
  StrLCopy(allocStrMem, Delim+StrMem, sPos-Delim-1); //-$00000003
  TsStrMem.Add(allocStrMem);
  StrDispose(allocStrMem);
end;
Saludos
 #413480  por WarZ0n3
 
Bueno gracias por sus comentarios

@Pink gracias por la aclaración pero no es necesario, como te decía esta función tiene como objetivo combinar pascal+asm, y sí, lo de lnStr lo sabia pero como te explicaba la idea es optimizar código(con el objetivo de correr mas rápido), también podria:
allocStrMem:=StrAlloc(StrLen(lnStr))
y con quitar un par de lineas se acorta la función(ya lo probé también), pero esto no tendría sentido como decía mi objetivo es usar ASM ademas de "alojarlo" en el Heap y jugar con la memoria... me gusta tener control de datos, punteros, etc.
Por lo menos a mi, no me gusta reservar mas espacio en la memoria de lo que voy a usar, esto para prevenir errores, desbordamientos, etc, ya que si seria un string terminado en nulo y no <delimitado> usaría StrCopy y ya(aun que no es para nada recomendable).
trabajar con punteros y demás produce fallos si no se tiene un control de flujo, por eso les produjo errores al principio, no por que strLcopy tenga un bug ni muchos menos, si no por que no se controla bien el array. veamos:
for i:=0 to length(tu_array)-1 do begin
         __ExtractMemString('$', pChar(palabras_defectuosas[i]), '&', TsStrMem);;
    end;
Esto puede producir errores por no controla correctamente la longitud del array, y digo puede, por que si no te tira ninguna excepción tiene suerte...

esta es la manera correcta(o que por lo menos la que hasta el momento ami nunca me dio errores )
for i:=0 to length(palabras_defectuosas)-1 do begin
    if palabras_defectuosas[i]>#0 then // controlamos que no sea mayor que cero
         __ExtractMemString('$', pChar(palabras_defectuosas[i]), '&', TsStrMem);;
    end;
también para limpiar la memoria podríamos usar al final o al principio(se si inicia el array):
ZeroMemory(@palabras_defectuosas, sizeof(palabras_defectuosas[i]));
y depende de la ocasión, tipo de dato, etc...
así como fillChar, en fin son simples consejos...
Saludos
 #413495  por Pink
 
Si pero si te fijas si ya tienes las posiciones para con las que se podría reservar sin pasar al código asm. osea es mas rápido una "Resta" Pos-Delim que todo lo que haces en asm.

no importa que no reserves para terminación nuala porque strlcopy lo coloca siempre, asi no deformas la cadena.



saludos