Question about M_String

Hi Kem,

I use the function RandomString from your M_String collection. As CharSet I use nearly all letters a-z, A-Z and Numbers 1-9 (ParamArray charSet as String: one String “abcdefghij …”) and I want 8 random characters at the end. Since there are no utf-8 special fonts I disabled ConvertEncoding.
I run all in a Loop for 1000 times. But after displaying all random strings it seems not to be completely random. For example no letter “a” or “A” at the first position of the string and some letters seems to appear more often in the strings. Do I made a mistake?

Cheers,
Thomas

// Kem Tekenay M_Strings
// Returns a random string of a specified length.
// If no charsets are specified, the entire ASCII range is used and the
// encoding of the string is set to nil.
  
  #if not DebugBuild
    #pragma BackgroundTasks False
    #pragma BoundsChecking False
  #endif
  
  if length <= 0 then return ""
  
  if zRnd is nil then zRnd = new Random
  
  dim completeCharSet as string
  dim s as string
  if charSet.Ubound = -1 then
    
    // Special handling
    s = Crypto.GenerateRandomBytes( length )
    
  else
    completeCharSet = join( charSet, "" )
    if completeCharSet = EmptyString then return EmptyString
    
    dim r() as string
    dim lastIndex as integer = length - 1
    redim r( lastIndex )
    
    dim chars() as string = split( completeCharSet, "" )
    dim lastCharIndex as integer = chars.Ubound
    
    for i as integer = 0 to lastIndex
      dim mb as MemoryBlock = Crypto.GenerateRandomBytes( 8 )
      dim seedValue as Int64 = mb.Int64Value( 0 ) // Close as I get get the securely randomizing this
      zRnd.Seed = seedValue 
      
      r( i ) = Chr(Asc(chars( zRnd.InRange( 0, lastCharIndex ) ) ) )
    next
    
    s = join( r, "" )           //.ConvertEncoding( completeCharSet.Encoding )
    
  end if
  
  return s

I ran a test loop of 1000 and, ironically, the very first result was “aWgnfSma”. Random is random so you can’t expect an even distribution. If you run it another 1000 times, I’d bet you’d see different oddities.

Just a note: If you’re using this for some secure purpose like a salt, you should use Crypto.RandomBytes instead.

I just ran the 1000-iteration loop three times to check the occurrence of each character on each pass. This doesn’t check for position, just occurrence. These are my results:

A = 107
B = 136
C = 129
D = 135
E = 126
F = 134
G = 123
H = 133
I = 129
J = 142
K = 136
L = 142
M = 135
N = 137
O = 132
P = 141
Q = 113
R = 127
S = 152
T = 126
U = 110
V = 145
W = 132
X = 141
Y = 130
Z = 136
a = 131
b = 114
c = 128
d = 108
e = 115
f = 142
g = 132
h = 122
i = 131
j = 110
k = 133
l = 120
m = 114
n = 136
o = 124
p = 141
q = 142
r = 147
s = 143
t = 125
u = 120
v = 134
w = 149
x = 126
y = 117
z = 125
0 = 127
1 = 103
2 = 119
3 = 108
4 = 141
5 = 126
6 = 147
7 = 123
8 = 117
9 = 131

A = 138
B = 141
C = 113
D = 127
E = 137
F = 110
G = 131
H = 122
I = 123
J = 117
K = 122
L = 130
M = 132
N = 121
O = 144
P = 125
Q = 126
R = 137
S = 111
T = 147
U = 139
V = 132
W = 124
X = 123
Y = 119
Z = 127
a = 125
b = 101
c = 132
d = 117
e = 133
f = 135
g = 119
h = 143
i = 131
j = 133
k = 118
l = 133
m = 126
n = 140
o = 131
p = 147
q = 133
r = 134
s = 123
t = 122
u = 147
v = 137
w = 132
x = 125
y = 136
z = 153
0 = 127
1 = 136
2 = 126
3 = 118
4 = 144
5 = 118
6 = 132
7 = 126
8 = 131
9 = 118

A = 150
B = 150
C = 138
D = 114
E = 153
F = 124
G = 124
H = 117
I = 131
J = 100
K = 125
L = 132
M = 153
N = 127
O = 123
P = 120
Q = 138
R = 148
S = 130
T = 138
U = 126
V = 134
W = 128
X = 147
Y = 121
Z = 125
a = 139
b = 140
c = 121
d = 126
e = 123
f = 121
g = 141
h = 122
i = 112
j = 120
k = 135
l = 135
m = 139
n = 107
o = 122
p = 138
q = 138
r = 116
s = 103
t = 130
u = 114
v = 128
w = 137
x = 120
y = 127
z = 116
0 = 139
1 = 121
2 = 131
3 = 123
4 = 154
5 = 126
6 = 138
7 = 118
8 = 127
9 = 137

Thank you very much.

I will change to Crypto.RandomBytes and try it again.

Thomas.

unfortunately …

I have again weird results.

There is no Crypto.RandomBytes function. Do I understand something wrong?

Thomas

There is definitely something wrong with my class. If I use your M_String all works fine.

Thomas

Sorry, it’s s = Crypto.GenerateRandomBytes( byteCount )

Now my solution works :slight_smile:

  // M_String Kem Tekinay
  // Returns a random string of a specified length.
  // If no charsets are specified, the entire ASCII range is used and the
  // encoding of the string is set to nil.
  
  #if not DebugBuild
    #pragma BackgroundTasks False
    #pragma BoundsChecking False
  #endif
  
  if length <= 0 then return ""
  
  if zRnd is nil then zRnd = new Random
  
  dim completeCharSet as string
  dim s as string
  
  completeCharSet = join( charSet, "" )
  
  dim r() as string
  dim lastIndex as integer = length - 1
  redim r( lastIndex )
  
  dim chars() as string = split( completeCharSet, "" )
  dim lastCharIndex as integer = chars.Ubound
  
  for i as integer = 0 to lastIndex
    dim mb as MemoryBlock = Crypto.GenerateRandomBytes( 8 )
    dim seedValue as Int64 = mb.Int64Value( 0 ) // Close as I get get the securely randomizing this
    zRnd.Seed = seedValue
    
    r( i ) = chars( zRnd.InRange( 0, lastCharIndex ) )
  next
  
  s = join( r, "" ).ConvertEncoding( completeCharSet.Encoding )
  
  return s
  

Request:

RandomString(8, "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789")

Thank you again Kem!
Thomas