in reply to Re^2: Need a wait to generate a 4 digit "PIN" number
in thread Need a wait to generate a 4 digit "PIN" number

That could result in something larger than 9999 (up to 65535) and it could result in 1, 2, 3 digit pins (you'll never get 0123, but you will get 123).

What's with quotes around variable names?
Why start with the hex form?
Why calculate a hash *and* a checksum?

Using a MD5 hash will produce a good distribution of PINs.
Solution using MD5 hash:

my $pinc = join('', $data1, $data2, $data3); my $pin = sprintf('%04d', unpack('N', md5($pinc)) % 10000);

Using CRC32 will *probably* produce a good distribution of PINs, but I don't personally know that.
Using CRC32 will probably be faster than MD5, but it probably won't be noticeable unless you do millions of these in a row.
Solution using CRC32:

my $pinc = join('', $data1, $data2, $data3); my $pin = sprintf('%04d', unpack('%32C*', $pinc) % 10000);

Replies are listed 'Best First'.
Re^4: Need a wait to generate a 4 digit "PIN" number
by jaiello (Novice) on Dec 16, 2007 at 07:35 UTC
    I quote the variables as they may contain *@%, etc. I figured it was safer. I started with hex as when I used a straight md5 hash, I did not get 4 digit numbers all the time. I don't entirely understand the code I used, but it worked, so I used it. So, that u=included a hash and a checksum. Why do you use '' as a separator in the join when it works without one? Thanks for the code snippets. I researched the modulus some but did not understand it very well, so I opted for a checksum. I'll probably use one in my application. I am sure you would cringe at the rest of my code. For example, I needed to strip both - and \r\n from a string but never managed to do it in one search/replace. So I had to do in on two lines: $data=~ s/\n\r//g; $data=~ s/-//g; Thanks!

      I quote the variables as they may contain *@%, etc. I figured it was safer.

      There's never any interpolation without quotes, and "*" and "%" are not special in string literals (although "*" is special in regex literals).

      All you achieve is to force the variable to become a string it it wasn't, but functions that expect strings (such as join) will already do that.

      I did not get 4 digit numbers all the time

      You still didn't. You need to add the leading zeroes if you want them. That's what the sprintf is for.

      I don't entirely understand the code I used, but it worked

      No, it didn't. It may have seemed to work for the input you gave, but you can get PINs outside the range you want, or your PINs weren't well distributed (i.e. they were predictable), or both.

      Why do you use '' as a separator in the join when it works without one?

      join won't work without a separator. $data1 was being used as the separator. It's much clearer to the person reading your code (the real user of your code) if you didn't use $data1 as the separator. The fact that you're confused about the need for a separator validates my point.

      I researched the modulus some but did not understand it very well,

      Modulus is the remainder of an integer division. For example,

      int(1234567 / 10000) = 123 1234567 % 10000 = 4567

      The following holds true:

      $x = int($x/$d) * $d + $x%$d

      For example,

      1234567 = 123 * 10000 + 4567 = int(1234567/10000) * 10000 + 1234567%10000

      The key thing is that the modulus will never be bigger than the divisor.
      % $d will result in a number in 0..($d-1).
      By using % 65536, you could get any number in 0..65535.
      By using % 10000, you'll only get numbers in 0..9999.
      (sprintf '%04d' will make that 0000..9999 by adding leading zeroes.)

      I needed to strip both - and \r\n from a string but never managed to do it in one search/replace

      s/\r\n|-//g

      If you want to remove "\r", "\n", and "-" (as opposed to "\r\n" and "-"):

      s/[\r\n-]//g

      You sure "\r" is actually there? "\r\n" gets transformed to "\n" automatically on a Windows machine.

      s/\n|-//g
      or
      s/[\n-]//g

      Best put - at the end of [...] or escape it ([...\-]) since it's used to do ranges ([a-z]).

      perlre

      Update: Added slashes missing in substitutions.

        Excellent! I normally join using "." and not using join. Admittedly, I did not look up the function and just used it as suggested. Normally I do lookup the functions and the semantics. Thanks for the quick tutorial on mods. I was clearly not thinking clearly. It is much clearer now. I have data pasted into a web form. Each row ends in - and some sort of newline. I tried a number of permutations of stripping the -\r\n. I first expected just \n, but that was not the case. Eventually, I figured out it really was \r\n. The only way to strip those was /\r\n//. Since the dash preceded the \r\n, I tried a number of ways before giving up and making two passes at it. thanks again
      The first argument to join is the string that will be inserted between the rest of the arguments.
      That is join '', $d1, $d2, $d3, $d4; is "$d1$d2$d3$d4" but join $d1, $d2, $d3, $d4; is "$d2$d1$d3$d1$d4".