Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Contar letras en un TMemo (https://www.clubdelphi.com/foros/showthread.php?t=39871)

egostar 31-01-2007 22:04:53

Contar letras en un TMemo
 
Hola amigos,

Tengo un pequeño problema al contar las letras dentro de un memo.

Tengo dos alternativas, una simple y otra menos ortodoxa.

Código Delphi [-]
// Aqui la simple
procedure TForm1.Memo1Change(Sender: TObject);
begin
  StaticText1.Caption := inttostr(Length(Memo1.Lines.Text));
end;

Código Delphi [-]
//Aqui la no muy Ortodoxa
procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  Case Key of
     8,46  : begin
          If Letras > 0 then begin
             Letras := Letras-1;
             StaticText1.Caption := inttostr(Letras);
          end;
     end;
     else begin
          case Key of
             13,16,20,35,36,37,38,39,40 : begin
             end;
             else begin
                    Letras := Letras+1;
                    StaticText1.Caption := inttostr(Letras);
             end;
          end;
     end;
  end;
end;

Mi problema existencial es que no quiero que cuente los enter en el memo solo las letras, numeros y espacios.

En la primera opcion que es la simple me cuenta los enter para sumar o para restar

En la segunda opcion no me suma los enter pero si los resta.

¿Hay algo que pueda hacer para que no me cuente los Enter?

Gracias anticipadas.

Caral 31-01-2007 22:18:52

Hola egostar
No se a que te refieres con los enter, supongo que a los espacios vacios entre las letras.
No se pero se me ocurre que si es text, por que no definir un:
Código Delphi [-]
If X = ' ' then
//otra cosa
Osea que si el espacio esta vacio no lo lea.
No se se me ocurre.
Saludos

egostar 31-01-2007 22:28:51

Hola Caral, gracias por tu interes.

Me refiero a los ENTER que son los saltos de linea, no a los espacios entre palabras, esos si los estoy contando.

Saludos.

Bicho 31-01-2007 22:34:04

Hola, quizá una función como esta te sirva:

Código Delphi [-]
 function Palabras(Cadena:string):integer;
 var
    n:integer;
    AntEspacio:boolean;
 begin
   AntEspacio:=FALSE;
   If Cadena='' then Result:=0 else Result:=1;
   for n:=1 to Length(Cadena) do
   begin
     if AntEspacio and
        (Cadena[n]<>' ')and
        (Cadena[n]<>#13)and
        (Cadena[n]<>#10)
                   then Inc(Result);

     AntEspacio:=(Cadena[n]=' ') or
                 (Cadena[n]=#13) or
                 (Cadena[n]=#10);
   end;
 end;

Saludos

ArdiIIa 31-01-2007 22:36:26

Veamos


Código Delphi [-]
procedure TForm1.ContarLetras(Sender: TObject);
Var
I,Z: Integer;
cTemp :  String;
begin
Z := 0;
cTemp := Memo1.Lines.Text;
For I := 1 To  Length(cTemp) DO
if ord(cTemp[i]) < 32 then
inc(Z);

ShowMessage( IntToStr( Length(cTemp) - Z ));

end;

seoane 31-01-2007 22:42:45

Volviendo al método numero uno, el ortodoxo :p

Supongo que esto funcionaría:
Código Delphi [-]
procedure TForm1.Memo1Change(Sender: TObject);
var
  Str: String;
  i,j: integer;
begin
  Str:= Memo1.Lines.Text;
  j:= 0;
  for i:= 1 to Length(Str) do
    if (Str[i] <> #13) and (Str[i] <> #10) then
      inc(j);
  StaticText1.Caption:= IntToStr(j);
end;

Aunque supongo que ya habrías pensado en una solución parecida, entonces me pregunto si lo que te preocupaba es el tiempo que se tarda en contar los caracteres. Si es así lo podemos afinar un poco mas:
Código Delphi [-]
function Longitud(Str: PChar): Integer;
asm
        MOV     Result,0
        DEC     EAX
@@SIG:
        INC     EAX
        CMP     BYTE PTR [EAX],0
        JE      @@SALIR
        CMP     BYTE PTR [EAX],13
        JE      @@SIG
        CMP     BYTE PTR [EAX],10
        JE      @@SIG
        INC     Result
        JMP     @@SIG
@@SALIR:
end;

procedure TForm1.Memo1Change(Sender: TObject);
begin
  StaticText1.Caption:= IntToStr(Longitud(PChar(Memo1.Lines.Text)));
end;

En cuanto al segundo método, es complicado, piensa que cuando usas Enter se introducen dos caracteres y no uno, que puedes seleccionar y borrar mas de un carácter a la vez y ya no hablamos si utilizas el portapapeles ...

egostar 31-01-2007 22:46:37

Muchas gracias ArdiIIa

Quedo de 10

Aqui pongo como quedó el código completo espero que sirva para futuras consultas.

Código Delphi [-]
unit UContadorLetras;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    StaticText1: TStaticText;
    Label1: TLabel;
    BitBtn1: TBitBtn;
    procedure FormShow(Sender: TObject);
    procedure Memo1Change(Sender: TObject);
    procedure ContarLetras;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Letras: Integer;

implementation

{$R *.DFM}

procedure TForm1.ContarLetras;
Var
  I,Z: Integer;
  cTemp :  String;
begin
  Z := 0;
  cTemp := Memo1.Lines.Text;
  For I := 1 to  Length(cTemp) do
      if ord(cTemp[i]) < 32 then
         inc(Z);
  StaticText1.Caption := IntToStr(Length(cTemp) - Z);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Letras := 0;
  StaticText1.Caption := inttostr(Letras);
end;

procedure TForm1.Memo1Change(Sender: TObject);
begin
  ContarLetras;
end;

end.

Saludos y nuevamente gracias.

egostar 31-01-2007 22:48:12

Vaya

Tambien este funcionó a la perfeccion.

Código Delphi [-]
unit UContadorLetras;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    StaticText1: TStaticText;
    Label1: TLabel;
    BitBtn1: TBitBtn;
    procedure FormShow(Sender: TObject);
    procedure Memo1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Letras: Integer;

implementation

{$R *.DFM}

procedure TForm1.FormShow(Sender: TObject);
begin
  Letras := 0;
  StaticText1.Caption := inttostr(Letras);
end;

procedure TForm1.Memo1Change(Sender: TObject);
var
  Str: String;
  i,j: integer;
begin
  Str:= Memo1.Lines.Text;
  j:= 0;
  for i:= 1 to Length(Str) do
    if (Str[i] <> #13) and (Str[i] <> #10) then
      inc(j);
  StaticText1.Caption:= IntToStr(j);
end;

end.

Muchas gracias seoane.

Caral 31-01-2007 22:55:36

Hola, Bueno, los dos funcionan muy bien y hacen casi lo mismo, pero:
Me he quedado con que cuentan tambien los espacios en blanco, como hacer para que no los cuente.
Osea contar letras, pues que cuente letras, no espacios entre ellas, al igual que no cuenta el enter o salto de renglon.
Saludos

egostar 31-01-2007 22:57:32

Perdon Bicho pero no vi tu post antes de contestar a los demas, gracias por el aporte.

Saludos.

egostar 31-01-2007 23:01:04

Cita:

Empezado por seoane
Aunque supongo que ya habrías pensado en una solución parecida, entonces me pregunto si lo que te preocupaba es el tiempo que se tarda en contar los caracteres. Si es así lo podemos afinar un poco mas:

Realmente no me preocupa el tiempo en el conteo, incluso es imperceptible, de todos modos estoy analizando tu código ASM que me parece muy interesante aunque un poco fuera de mi alcance en este momento:D.

Saludos.

ArdiIIa 31-01-2007 23:01:05

Cita:

Empezado por Caral
Hola, Bueno, los dos funcionan muy bien y hacen casi lo mismo, pero:
Me he quedado con que cuentan tambien los espacios en blanco, como hacer para que no los cuente.
Osea contar letras, pues que cuente letras, no espacios entre ellas, al igual que no cuenta el enter o salto de renglon.
Saludos

Código Delphi [-]
procedure TForm1.ContarLetras;
Var
  I,Z: Integer;
  cTemp :  String;
begin
  Z := 0;
  cTemp := Memo1.Lines.Text;
  For I := 1 to  Length(cTemp) do
      if ord(cTemp[i]) < 33 then
         inc(Z);
  StaticText1.Caption := IntToStr(Length(cTemp) - Z);
end;

egostar 31-01-2007 23:05:03

Cita:

Empezado por Caral
Hola, Bueno, los dos funcionan muy bien y hacen casi lo mismo, pero:
Me he quedado con que cuentan tambien los espacios en blanco, como hacer para que no los cuente.
Osea contar letras, pues que cuente letras, no espacios entre ellas, al igual que no cuenta el enter o salto de renglon.
Saludos

Usando el mismo procedimiento de seoane, aqui esta para no contar espacios tampoco

Código Delphi [-]
procedure TForm1.Memo1Change(Sender: TObject);
var
  Str: String;
  i,j: integer;
begin
  Str:= Memo1.Lines.Text;
  j:= 0;
  for i:= 1 to Length(Str) do
    if (Str[i] <> #13) and (Str[i] <> #10) and (Str[i] <> #32) then
      inc(j);
  StaticText1.Caption:= IntToStr(j);
end;

Saludos

Caral 31-01-2007 23:09:18

Hola ArdiIIa
Perdona, pero lo haces facil.:D
Como buen aprendiz, no me quedo solo con el cambio de 32 x 33
Por que?
a que se debe?
tiene relacion con la cantidad de letras del abecedario?
El #13 es enter
El #33 es Espacio?
Me lo explicas, por favor.:D
Saludos

Caral 31-01-2007 23:14:43

Interesante, las dos opiones.
Varian en muy poco, pero tienen el mismo efecto.
No se para que me pueda servir el codigo, pero una cosa si tengo clara.
Aqui se aprende muchisimo y eso que no hice yo la pregunta.:D
Saludos Maestros

egostar 31-01-2007 23:21:20

Cita:

Empezado por Caral
Interesante, las dos opiones.
Varian en muy poco, pero tienen el mismo efecto.
No se para que me pueda servir el codigo, pero una cosa si tengo clara.
Aqui se aprende muchisimo y eso que no hice yo la pregunta.:D
Saludos Maestros

Pues mira, te comento para que se va a usar, tengo un cliente que escribe articulos para una revista, resulta que la editora le pide que sean de una cantidad de caracteres máxima, entonces con ese código no tiene que estar contando letra por letra cuantas lleva, una vez que termine con un botón lo quiere mandar por correo, pero eso ya es otra historia que solucionaré con Indy.

Bueno a grandes rasgos para eso lo requeria.

Saludos y gracias por el interes y sobre todo por la rapidez de sus respuestas.

Caral 31-01-2007 23:25:28

Hola
Me imagine que por ai podia andar, pero pense en una aplicacion de tipo didactica, para estudiantes, creia que podia ser para algo asi.
Pero no deja de ser muy interesantes las posivilidades del codigo de estos maestros.
Saludos

ArdiIIa 31-01-2007 23:27:23

Cita:

Empezado por Caral
Hola ArdiIIa
Perdona, pero lo haces facil.:D
Como buen aprendiz, no me quedo solo con el cambio de 32 x 33
Por que?
a que se debe?
tiene relacion con la cantidad de letras del abecedario?
El #13 es enter
El #33 es Espacio?
Me lo explicas, por favor.:D
Saludos

Está claro, es el código ASCII de cada letra, ESPACIO = 32
luego si le dices que incremente Z cada vez que el caracter sea inferior a 32, el resultado es lo que se esperaba, todos los caracteres por debajo de 32, son caracteres de control, no letras. así de sencillo.

Caral 01-02-2007 00:09:23

Muchas Gracias por tu explicacion ArdiIIa
Me queda claro.
Saludos

ArdiIIa 01-02-2007 01:38:11

Por abundar un poquito mas y examinando el ASM de seoane aún se puede optimizar algo mas quitando unas líneas y cambiando otras, seguramente ganemos en rapidez...

Código Delphi [-]
function Longitud(Str: PChar): Integer;
asm
        MOV     Result,0
        DEC     EAX
@@SIG:
        INC     EAX
        CMP     BYTE PTR [EAX],0
        JE      @@SALIR
        CMP     BYTE PTR [EAX],33
        JB      @@SIG
        INC     Result
        JMP     @@SIG
@@SALIR:
end;


La franja horaria es GMT +2. Ahora son las 08:15:27.

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