Jump to content


Photo

Generar números y letras Aleatorios


  • Please log in to reply
31 replies to this topic

#21 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 02:12 PM

Observa el código monchito_elroro, estudia. Si no te es molestia eso queda de tarea.

Pista:

* ¿Cuántos carácteres tendremos en CHARS sin contar la Ñ, y obviamente, contando también los numéricos?

* Sabiendo que para los carácteres diferentes a la Ñ no se necesitó hacer "magia", que debería cambiar?

* La solución no es tan diferente al de mi primer propuesta. Fíjate en donde está el pequeño bug. Recuerda que Random(Nro) regresa números enteros en el rango [0, Nro) es decir mayores e iguales a cero y menores al número pasado como parámetro. Y que para leer un string posición a posición esta comienza en 1.

 

Saludos,


  • 0

#22 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 260 posts

Posted 18 December 2015 - 02:15 PM

Ya lo encontre faltaba poner el randomize, lo he puesto por aquí y de momento me funciona: :)


php
  1. function TForm1.RandomStringsKeys(KeysCount, KeysLength: integer;
  2.   Separator: char): string;
  3. const
  4.   CHARS = 'ABCDEFGHIJKLMNÑOPQRSTUVWXYZ0123456789';
  5. var k, l, c: integer;
  6.     rnd: string;
  7. begin
  8.   rnd := '';
  9.   Randomize;   // acá lo puse y de momento me funciona
  10.   for k := 1 to KeysCount do
  11.   begin
  12.     for l := 1 to KeysLength do
  13.     begin
  14.       c := Random(37) + 1;
  15.       case c of
  16.          15: rnd := rnd + CHARS[c] + CHARS[c+1];
  17.          1..14: rnd := rnd + CHARS[c];
  18.       else rnd := rnd + CHARS[c+1];
  19.       end;
  20.     end;
  21.  
  22.     if k <> KeysCount
  23.        then rnd := rnd + Separator;
  24.   end;
  25.   result := rnd;

Ahora como hago para hacerlo funcionar sin la Ñ, gracias por su ayuda de antemano.


  • 0

#23 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 02:19 PM

Randomize no debería utilizarse dentro de la función. Randomize debe invocarse una sola vez, y generalmente, se lo suele hacer al inicio del programa o bien en el "lugar más cercano" en donde se espera producir los números pseudoaleatorios.

De ponerlo dentro de la función estarás reseteando el valor de semilla cada vez que invocas a la función. Si bien no es pecado haberlo hecho, tampoco es bueno.

 

Saludos,


  • 0

#24 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 260 posts

Posted 18 December 2015 - 02:24 PM

Tiene razón amigo Delphius lo he puesto en el evento create del form y me funciona igual, gracias por sus consejos los tendré presentes.


php
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   Randomize;

Ahora sigo viendo que número puedo cambiar para omitir la letra Ñ ...


  • 0

#25 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 02:41 PM

Tiene razón amigo Delphius lo he puesto en el evento create del form y me funciona igual, gracias por sus consejos los tendré presentes.


php
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   Randomize;

Ahora sigo viendo que número puedo cambiar para omitir la letra Ñ ...

 

¡Estoy seguro que tu puedes! sólo recuerda las pistas que he dejado unos mensajes antes. Luego ve mi código inicial y empieza a responderlas. A lo largo del hilo está explicado todo.

 

Saludos,


  • 0

#26 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 260 posts

Posted 18 December 2015 - 03:09 PM

Estoy probando cambiando el número 37 por 36.


php
  1.       begin
  2.       c := Random(36) + 1;    // original 37
  3.       case c of

Pero unas veces me da cinco caracteres otras 6 y otras 7  :sad:


  • 0

#27 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 December 2015 - 05:06 PM

Permitidme un ejemplo sencillo con caracteres ASCII de la misma tabla:


delphi
  1. function Clave: String;
  2. const
  3. {$J+}
  4.   First: boolean = true;
  5. {$J-}
  6. var
  7.   i, n, v: integer;
  8. begin
  9.   Result:= '';
  10.   if First then Randomize;
  11.   First:= false;
  12.  
  13.   for i:=1 to 5 do
  14.   begin
  15.     for n:= 1 to 5 do
  16.     begin
  17.       V:= ord('0') + Random(36);
  18.       if V > ord('9') then V:= V + 7;
  19.       Result:= Result + CHAR(V);
  20.     end;
  21.     if i<5 then Result:= Result + '-';
  22.   end;
  23. end; 

La función solita sabe cuando llamar a Randomize.

Adaptarlo a un número mayor de caracteres, de grupos o distinto separador, es bien sencillo.

 

Saludos.


  • 0

#28 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 05:08 PM

Monchito_elroro, estás bastante cerca, simplemente estás mirando la función equivocada. El asunto es que si se puede prescindir de la Ñ no hace falta la artimaña de evaluar el valor de c para determinar a que posición dentro de CHARS corrresponde para obtener el carácter aleatorio que ha sido necesaria armar para este caso tan particular. Mi primer código, que no trabaja con Ñ tiene un pequeño defecto en calcular la posición, pero puede corregirse fácilmente:

 

Sabiendo que tenemos 26 letras (no contamos la Ñ) y 10 números, sabemos entonces que los números aleatorios deben ir desde 1..36. El "problemita" es que Random(Nro) nos genera números en el rango 0..Nro - 1.

 

Tenemos que hacer que para un número R aleatorio, R := Random(algo) se corrresponda con una posición P válida de carácter. Entonces:

 

R = 0, -> P = 1

R = 1, -> P = 2

...

R = Maximo, -> P = 36

 

Sabiendo entonces que si P resulta ser R + 1, el máximo valor que puede tener R será P - 1 = 36 - 1 = 35.

 

Entonces el rango de valores aleatorios que debemos conseguir debe ser 0..35 de allí que Random(36).

 

Ahora efectivamente ya con esto en mente es que podemos hacer CHARS[Random(36) + 1] pero mi código original terminaba haciendo una operación equivalente a esto: CHARS[Random(37)] que no es lo mismo.

 

Haciendo esta simple corrección a mi 1ra propuesta tiene (y estoy completamente seguro) que funcionar sin problema alguno:


delphi
  1. function TForm1.RandomStringsKeys(KeysCount, KeysLength: integer;
  2. Separator: char): string;
  3. const
  4. CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  5. var k, l: integer;
  6. rnd: string;
  7. begin
  8. rnd := '';
  9. for k := 1 to KeysCount do
  10. begin
  11. for l := 1 to KeysLength do
  12. rnd := rnd + CHARS[Random(36) + 1];
  13.  
  14. if k <> KeysCount
  15. then rnd := rnd + Separator;
  16. end;
  17. result := rnd;
  18. end;

Saludos,


  • 0

#29 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 05:30 PM

Permitidme un ejemplo sencillo con caracteres ASCII de la misma tabla:


delphi
  1. function Clave: String;
  2. const
  3. {$J+}
  4.   First: boolean = true;
  5. {$J-}
  6. var
  7.   i, n, v: integer;
  8. begin
  9.   Result:= '';
  10.   if First then Randomize;
  11.   First:= false;
  12.  
  13.   for i:=1 to 5 do
  14.   begin
  15.     for n:= 1 to 5 do
  16.     begin
  17.       V:= ord('0') + Random(36);
  18.       if V > ord('9') then V:= V + 7;
  19.       Result:= Result + CHAR(V);
  20.     end;
  21.     if i<5 then Result:= Result + '-';
  22.   end;
  23. end; 

La función solita sabe cuando llamar a Randomize.

Adaptarlo a un número mayor de caracteres, de grupos o distinto separador, es bien sencillo.

 

Saludos.

 

Interesante propuesta. Yo soy un enamorado de hacer este tipos de cosas por la vía "difícil" y emplear un "vector" de string. Me resulta más limpio y a la vez flexible para que en un futuro pueda incorporar más carácteres y no tener que depender y estar calculando la posición en la tabla de carácteres ASCII.

 

Podríamos jugar incluso hasta con la posibilidad de que pase por parámetros si debe usarse los carácteres "extraños" o "especiales" o no.

 

Saludos,


  • 0

#30 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 December 2015 - 05:40 PM

Interesante propuesta. Yo soy un enamorado de hacer este tipos de cosas por la vía "difícil" y emplear un "vector" de string. Me resulta más limpio y a la vez flexible para que en un futuro pueda incorporar más carácteres y no tener que depender y estar calculando la posición en la tabla de carácteres ASCII.
 
Podríamos jugar incluso hasta con la posibilidad de que pase por parámetros si debe usarse los carácteres "extraños" o "especiales" o no.


Si, te permite mas cosas y eso es bueno. Yo he usado el cálculo de caracteres ASCII en numerosas ocasiones para convertir a hexadecimal a bajo nivel, usando sólo API. Quería mostrar como hacerlo en este caso.
En el ejemplo muestro también como independizar la función de randomize jugando con directivas para conseguir algo que en C se llaman variables estáticas de una función. Delphi carece de ese concepto, pero se puede trampear para conseguir cambiar el valor de una constante y conseguir algo muy parecido a una variable estática de C.

Esta forma de usar randomize, puede no ser interesante, puesto que el programador ha podido usarla antes y no fijarse en que esta función lo hace. Se trata de jugar con el código...


Saludos.
  • 0

#31 monchito_elroro

monchito_elroro

    Advanced Member

  • Miembros
  • PipPipPip
  • 260 posts

Posted 18 December 2015 - 09:38 PM

Muchas gracias Delphius y Escafranda estaba tratando de entender  :)  :)  como operaban los códigos que me compartieron y al principio entendía un poco pero luego me perdí :.

Lo importante es que ambas soluciones trabajan perfectamente para lo que fueron creadas (y) Muchas gracias, ahora puedo generar códigos aleatorios como por ejemplo:

 

7WZVX-1MCSK-GICZR-7CIG1-A82T2

JMCEK#77PQS#6UK2O#OU5VR#34SDF

4PJ0R-PJQUW-8V4SX-S9I5D-ZOEAD

 

También quería compartir uno que acabo de realizar de la mezcla de otros códigos es este:

 



php
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   Randomize;
  4.  
  5. procedure TForm1.Button2Click(Sender: TObject);
  6. const
  7.   cValoresNum      = '0123456789';
  8.   cValoresAlpha    = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  9.   cValoresAlphaNum = cValoresNum + cValoresAlpha;
  10. var
  11.   b, c:integer;
  12.   var key1, key2, key3, key4, key5 : string;
  13.  
  14. begin
  15.   begin
  16.   //Randomize;   // ponerlo en el create del form
  17.        for b := 1 to 5 do
  18.        begin
  19.        key1:=key1+cValoresAlphaNum[ Random(length(cValoresAlphaNum))+1 ];
  20.  
  21.        key2:=key2+cValoresAlphaNum[ Random(length(cValoresAlphaNum))+1 ];
  22.        key3:=key3+cValoresAlphaNum[ Random(length(cValoresAlphaNum))+1 ];
  23.        key4:=key4+cValoresAlphaNum[ Random(length(cValoresAlphaNum))+1 ];
  24.        key5:=key5+cValoresAlphaNum[ Random(length(cValoresAlphaNum))+1 ];
  25.        end;
  26.   end;
  27.   Edit1.Text:=key1+'-'+key2+'-'+key3+'-'+key4+'-'+key5;

También me funciona perfecto  :)  y el resultado es este:

QZTK5-GS0RS-85OSX-K21QN-M2YXH
3H2RV-OE9YR-D9IVR-VN52U-S1JSA
X7BNN-J2E8F-I5R97-Y9HAL-7SO02

 

Si en algo estoy fallando por favor puedan corregirme.


  • 0

#32 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 18 December 2015 - 10:53 PM

Tu código hace bien lo previsto. Mi ojo compilador detecta que hay un begin y un end demás en el Button2Click.

 

Saludos,


  • 0




IP.Board spam blocked by CleanTalk.