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

This is not homework and I didn't have a code sample as I was trying to find a way to do this. I have the bits already concatenated. I have a hex MD5hash of the concatenated string.

You gave me the thought to use a Solaris like SUM of the string. So I did this:

$pinc=join("$data1","$data2","$data3"); $digest2 = md5_hex($pinc); $pin=unpack("%32C*",$digest2) % 65535; print "[$pinc],[$digest2],[$pin]";

and I get:

[ilikeyoumy@email.comilikepie] [be256d5090d0875e7812428991d70026] [1961]

This seems to work.

Do you have an opinion on this?

Thanks!

Replies are listed 'Best First'.
Re^3: Need a wait to generate a 4 digit "PIN" number
by ikegami (Patriarch) on Dec 16, 2007 at 05:44 UTC

    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);
      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.

        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".