Un veloce algoritmo digest

Nella fattispecie, per esigenze del cliente e specificità del prodotto, uno stesso codice articolo (che è discriminante nel database) deve essere associato a diverse entità ed apparire effettivamente come tanti prodotti "differenti" (con tanto di descrizione diversa, ottimizzata per la particolare "visualizzazione"). Occorre dunque creare on the fly altri codici per quel prodotto, non pseudocasuali poiché dovrò poi poter ricostruire esattamente il nuovo codice quando effettuerò i vari SQL UPDATE in fase di gestione (l'interfaccia preleva ogni prefissato intervallo di tempo i dati aggiornati e li riversa su MySQL).
Una soluzione è quella di applicare un algoritmo digest NON al codice (che è sempre uguale - quello nel gestionale) ma alla descrizione del prodotto (che invece cambia), leggerne l'hash e concatenarlo al codice con uno score - per distinguerlo visivamente dalla radice del codice, cosa necessaria per il gestore umano che leggerà gli ordini.
La cosa funziona e l'e-commerce digerisce il digest :) tutti i codici articolo sono caricati (e moltiplicati alla bisogna) ed è semplice, in fase di aggiornamento, discriminarli.
Per velocizzare l'elaborazione di decine di migliaia di codici articolo e relative descrizioni, senza scomodare robusti algoritmi digest con peculiarità crittografiche (secure-digest) come FNA, SHA (nelle varie salse) o MD5, è stata implementata una velocissima function che ritorna "l'impronta", l'hash, della stringa contenente la descrizione.
Ciò è fatto utilizzando l'ordinale ASCII e l'aritmetica modulare (solo interi, siamo in Teoria dei Numeri e prendiamo solo roba robusta eh!).
Siamo tutti abituati giornalmente ad usarla in base 60 (grazie babilonesi ovunque voi siate :) )... ma dove? Per l'orario naturalmente: si parte da zero, si arriva a 59 e quindi il 60 è... nuovamente zero.
L'operatore modulo (di un numero intero) restituisce il resto della divisione di quel numero per la base utilizzata.
Ad esempio volendo calcolare 81 mod 60, dovremo calcolare il quoziente (intero) di 81 su 60 e prenderne il resto.
Alcuni esempi:
81 mod 60=21
260 mod 60=20
21 mod 60=21 (non è divisibile interamente per cui prendo il numero tal quale come "resto").
Desiderando un hash digest (quindi lunghezza fissa) per le necessità del caso limitato a 3 caratteri, l'algoritmo è:
1. iterazione sulla stringa, char a char, calcolando e sommando l'ordinale ASCII mediante ORD.
2. calcolare ORD mod BASE (nello specifico 999)
3. aggiungere tanti zeri a destra fino ad avere una stringa lunga 3 caratteri o lunga quanto necessita.
Di seguito il codice in versione compatta ed estesa per una maggiore leggibilità in fondo... "c'è più di un modo per farlo" (cit. Larry Wall) :)
#!/usr/bin/perl use strict; use warnings; my $text=q{Velocissimo digest per avere "l'impronta" di una stringa}; my $modulus=999; print moDigest($text,$modulus); exit; # versione compatta della sub sub moDigest { my $value; map{$value+=ord($_)}map(substr($_[0],$_,1),0..length($_[0])-1); $value%=$_[1]; while (length($value)<length($_[1])){$value.='0'} return $value } } # versione estesa sub moDigestExt { my $text=shift; my $modulus=shift; my @arrayOfChar=split('',$text); my $value=0; foreach my $char(@arrayOfChar) { $value=$value+ord($char); }; $value = $value % $modulus; while (length($value)<length($modulus)){ $value.='0' } return $value; }
Buon digest :)