Portal    Foro    Buscar    FAQ    Registrarse    Conectarse


Publicar nuevo tema  Responder al tema 
Página 1 de 1
 
 
Clave De Identificación única —de Nuevo—
Autor Mensaje
Responder citando   Descargar mensaje  
Mensaje Clave De Identificación única —de Nuevo— 
 
Aunque este tema se ha tratado en dos ocasiones —la primera de manera tangencial en 2016 y la siguiente este mismo año— al menos en este foro, creo que se puede aportar algo nuevo a este asunto:

https://foro.gambas-es.org/viewtopi...ghlight=#p34850
https://foro.gambas-es.org/viewtopic.php?f=5&t=7543&start=0

La cuestión es generar muy rápida y sencillamente una clave única, o casi única, y que sea lo más corta posible. En uno de los hilos se propone el uso de uuidgen, pero las claves obtenidas son muy largas. La otra manera es emplear fecha y hora. La manera más sencilla es colocar como cadena el año, mes, día, hora, minuto y segundo desde Now(). Aunque funciona, es mejorable. Sus defectos son la longitud y que sólo se puede generar una por segundo. En cuanto a la longitud se puede solucionar empleando una codificación más eficiente, colocando directamente el número de segundos de Now() e, incluso mejor, pasándola a Hex. Se proponía en su día:

strId = Hex(CFloat(Now) * 86400000)


Limpio, eficaz y en una sola línea. Pero, desde luego, sólo se puede generar una por segundo. Y, claro, no es única o casi.
El problema del «segundo» se puede solucionar añadiendo Timer, que da una fracción de segundo —aunque no sincronizada con Now(), pero para esta aplicación, no es relevante—.

sIzq = Hex(CFloat(Now) * 86400, 10) & Hex(Frac(Timer) * 1e6, 5)


Y ya puestos a reducir, en lugar de emplear base 16, podemos emplear base 64, y así usamos bastantes caracteres imprimibles, en lugar de los 16 conocidos.
El siguiente código emplea los segundos totales de Now() —10 dígitos hexadecimales— más microsegundos como fracción de segundo de Timer —5 dígitos hexadecimales—. Se emplea base 64 por la facilidad de la transformación, ya que cada tres dígitos hex, se transforman en dos en b64, por lo que no hay que manejar ese «peazo» número:

Public Function GenerarID() As String
  ' **** Generador de clave de IDentificación única
  ' <<<< Devuelve una ID como cadena de texto.
  ' >>>> No necesita argumentos. Emplea funciones de tiempo.
  
  ' Genera una clave haxadecimal de diez dígitos con el día hasta los segundos
  ' (cienmilésima de día aprox.) y otra de cinco dígitos con la parte fraccional
  ' de Timer.
  ' Luego la pasa de base 16 a base 64 tomando los dígitos de tres en tres y
  ' obtiene dos. De quince dígitos base 16 pasa a 10 base 64.

  Dim sB64 As String    ' Conjunto de dígitos en base 64
  Dim iSup As Integer   ' Dígito superior en B64
  Dim iInf As Integer   ' Dígito inferior en B64
  Dim sIzq As String    ' Fracción que queda por leer de base 16
  Dim sDer As String    ' Fracción 3 dígitos base 16
  Dim sRes As String    ' Resultado. Acumulador
  Dim iPas As Integer   ' Variable de paso

  sB64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  sIzq = Hex(CFloat(Now) * 86400, 10) & Hex(Frac(Timer) * 1e6, 5)
  sDer = ""
  sRes = ""
  Do Until Len(sIzq) = 0
    sDer = Right(sIzq, 3)
    sIzq = Left(sIzq, -3)
    iPas = Val("&" & sDer)
    iSup = iPas \ 64
    iInf = iPas Mod 64
    sRes = sB64[iSup] & sB64[iInf] & sRes
  Loop
  Return sRes
End


Puede generar un código —en mi ordenador— en unas 4,5 millonésimas de segundo. Quizá ésa es su debilidad: un equipo cinco veces más rápido que el mío podría generar dos códigos iguales seguidos. Tiene una solución obvia, pero creo que así es suficiente para la mayoría de las aplicaciones. En cuanto a la universalidad, existen dos consideraciones:
Por «arriba», el ciclo se repite cada 30.000 años, más o menos. Sin problema, de hecho, se podría reducir la longitud de la clave quitando los valores más significativos, a razón de un factor 64 por cada uno —un dígito nos lleva a un ciclo de unos 500 años, dos, ojo, a poco más de siete—.
Por «abajo», se genera un código distinto por cada millonésima de segundo, aunque existe el desfase comentado, pero al final la secuencia es la misma. Por tanto, existe una posibilidad elevada de que haya dos equipos que generen el mismo código. Depende de la necesidad de unicidad que realmente necesites, y la rapidez. Si quieres un código virtualmente único, pero largo y lento, uuidgen, sin duda. Si quieres algo más de andar por casa, con una unicidad aceptable, pero rápido como la cagalera y breve como la felicidad, éste que presento.
Y, como para muestra un botón, dejo ejemplos de códigos generados lo más rápidamente posible con mi equipo —como veis, la diferencia es de 22 ó 23 letras dentro del sistema b64, que se corresponden con esas 22 millonésimas de segundo: Debug tarda más que la asignación directa a una matriz—:

Mht5utsGuf
Mht5utsGuw
Mht5utsGvC
Mht5utsGvT
Mht5utsGvl
Mht5utsGv2
Mht5utsGwH
Mht5utsGwZ
Mht5utsGwq
Mht5utsGw8
Mht5utsGxN
Mht5utsGxe
Mht5utsGxw
Mht5utsGyB
Mht5utsGyT

 



 
última edición por Grandamakulo el Martes, 17 Septiembre 2019, 17:53; editado 2 veces 
Grandamakulo - Ver perfil del usuarioEnviar mensaje privadoVisitar sitio web del usuario 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: Clave De Identificación única —de Nuevo— 
 
¿Has probado esto?

Public function generaId() as string

 return Base64(Hex(CFloat(Now) * 86400, 10) & Hex(Frac(Timer) * 1e6, 5))

end

 




===================
No podemos regresar
 
shordi - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: Clave De Identificación única —de Nuevo— 
 
Hola, Shordi:
La función Base64 pasa a dicha base los bytes de una cadena, no cambia de base. De hecho, ocupa un 33% más que la propia cadena que transforma.

Con este ejemplo se ve más fácil:

Public Sub Main()

  Dim sB64 As String    ' Conjunto de dígitos en base 64
  Dim iSup As Integer   ' Dígito superior en B64
  Dim iInf As Integer   ' Dígito inferior en B64
  Dim sIzq As String    ' Fracción que queda por leer de base 16
  Dim sDer As String    ' Fracción 3 dígitos base 16
  Dim sRes As String    ' Resultado. Acumulador
  Dim iPas As Integer   ' Variable de paso

  Dim Alfa As Float
  Dim Beta As Float
  
  Alfa = CFloat(Now)
  Beta = Timer

  sB64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  sIzq = Hex(Alfa * 86400, 10) & Hex(Frac(Beta) * 1e6, 5)
  sDer = ""
  sRes = ""
  Do Until Len(sIzq) = 0
    sDer = Right(sIzq, 3)
    sIzq = Left(sIzq, -3)
    iPas = Val("&" & sDer)
    iSup = iPas \ 64
    iInf = iPas Mod 64
    sRes = sB64[iSup] & sB64[iInf] & sRes
  Loop
  
  Debug "ID"
  Debug "Sólo segundos HEX       : " & Hex(Alfa * 86400000)
  Debug "Segundos y fracción HEX : " & Hex(Alfa * 86400, 10) & Hex(Frac(Beta) * 1e6, 5)
  Debug "Segundos y fracción b64 : " & sRes
  Debug "Segundos y fracción b64$: " & Base64(Hex(Alfa * 86400, 10) & Hex(Frac(Beta) * 1e6, 5))

End


Éste es el resultado:

ID
Sólo segundos HEX       : C3BB53E9C289
Segundos y fracción HEX : 321B79D571261DB
Segundos y fracción b64 : Mht51XEmHb
Segundos y fracción b64$: MzIxQjc5RDU3MTI2MURC


PS.—Editado para usar los mismos datos de fecha y segundos en la generación de ID
 



 
última edición por Grandamakulo el Martes, 17 Septiembre 2019, 19:38; editado 1 vez 
Grandamakulo - Ver perfil del usuarioEnviar mensaje privadoVisitar sitio web del usuario 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: Clave De Identificación única —de Nuevo— 
 
Ok, no los había contado. Si la diferencia de tamaño es tan importante, llevas razón.

Pero no negarás que lo otro es más para ceporros apresurados como yo...
 




===================
No podemos regresar
 
shordi - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: Clave De Identificación única —de Nuevo— 
 
shordi escribió: [Ver mensaje]
Ok, no los había contado. Si la diferencia de tamaño es tan importante, llevas razón.

Pero no negarás que lo otro es más para ceporros apresurados como yo...

     
 



 
Grandamakulo - Ver perfil del usuarioEnviar mensaje privadoVisitar sitio web del usuario 
Volver arribaPágina inferior
Responder citando   Descargar mensaje  
Mensaje Re: Clave De Identificación única —de Nuevo— 
 
shordi escribió: [Ver mensaje]
Ok, no los había contado. Si la diferencia de tamaño es tan importante, llevas razón.

Pero no negarás que lo otro es más para ceporros apresurados como yo...


       
 



 
gambafeliz - Ver perfil del usuarioEnviar mensaje privado 
Volver arribaPágina inferior
Mostrar mensajes anteriores:    
 
OcultarTemas parecidos
Tema Autor Foro Respuestas último mensaje
No hay nuevos mensajes Control Editor: Colorear Palabras Clave jsbsan Controles/Librerías/Componentes 0 Martes, 29 Marzo 2011, 10:23 Ver último mensaje
jsbsan
No hay nuevos mensajes Clave Primaria Shell Bases de Datos 5 Sabado, 11 May 2013, 10:31 Ver último mensaje
Shell
No hay nuevos mensajes La Clave Rosetta Shell General 4 Jueves, 10 Diciembre 2015, 05:19 Ver último mensaje
Ricardo Prieto
No hay nuevos mensajes Diccionarios Clave-valor calcena General 12 Lunes, 16 Octobre 2017, 18:38 Ver último mensaje
jguardon
 

Publicar nuevo tema  Responder al tema  Página 1 de 1
 

Usuarios navegando en este tema: 0 registrados, 0 ocultos y 1 invitado
Usuarios registrados conectados: Ninguno


 
Lista de permisos
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas
No puede adjuntar archivos
Puede descargar archivos
No puede publicar eventos en el calendario



  

 

cron