Monday, February 15, 2010

Generate an alphanumeric Random Code, C#

        To generate an alphanumeric Random code

         ///

        /// Public static function Generate Random Code
        /// generate the random code
        /// Created By:   Munesh
        /// Created Date: Feb 10, 2010
        ///

        /// string
        public static string GenerateRandomCode()
        {
            int _minLength = 6, _maxLength = 6;

            string _charsLCase = "abcdefgijkmnopqrstwxyz";
            string _charsUCase = "ABCDEFGHJKLMNPQRSTWXYZ";
            string _charsNumeric = "23456789";

            // Create a local array containing supported Verification Code characters
            char[][] _charGroups = new char[][]
            {
                _charsLCase.ToCharArray(),
                _charsUCase.ToCharArray(),
                _charsNumeric.ToCharArray(),
                //PASSWORD_CHARS_SPECIAL.ToCharArray()
            };

            // Use this array to track the number of unused characters in each
            // character group.
            int[] _charsLeftInGroup = new int[_charGroups.Length];

            // Initially, all characters in each group are not used.
            for (int i = 0; i < _charsLeftInGroup.Length; i++)
                _charsLeftInGroup[i] = _charGroups[i].Length;

            // Use this array to track (iterate through) unused character groups.
            int[] _leftGroupsOrder = new int[_charGroups.Length];

            // Initially, all character groups are not used.
            for (int i = 0; i < _leftGroupsOrder.Length; i++)
                _leftGroupsOrder[i] = i;

            // Because we cannot use the default randomizer, which is based on the
            // current time (it will produce the same "random" number within a
            // second), we will use a random number generator to seed the
            // randomizer.

            // Use a 4-byte array to fill it with random bytes and convert it then
            // to an integer value.
            byte[] _randomBytes = new byte[4];

            // Generate 4 random bytes.
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            rng.GetBytes(_randomBytes);

            // Convert 4 bytes into a 32-bit integer value.
            int _seed = (_randomBytes[0] & 0x7f) << 24 |
                        _randomBytes[1] << 16 |
                        _randomBytes[2] << 8 |
                        _randomBytes[3];

            // Now, this is real randomization.
            Random random = new Random(_seed);

            // This array will hold password characters.
            char[] _verificationCode = null;

            // Allocate appropriate memory for the password.
            if (_minLength < _maxLength)
                _verificationCode = new char[random.Next(_minLength, _maxLength + 1)];
            else
                _verificationCode = new char[_minLength];

            // Index of the next character to be added to password.
            int _nextCharIdx;

            // Index of the next character group to be processed.
            int _nextGroupIdx;

            // Index which will be used to track not processed character groups.
            int _nextLeftGroupsOrderIdx;

            // Index of the last non-processed character in a group.
            int _lastCharIdx;

            // Index of the last non-processed group.
            int _lastLeftGroupsOrderIdx = _leftGroupsOrder.Length - 1;

            // Generate password characters one at a time.
            for (int i = 0; i < _verificationCode.Length; i++)
            {
                // If only one character group remained unprocessed, process it;
                // otherwise, pick a random character group from the unprocessed
                // group list. To allow a special character to appear in the
                // first position, increment the second parameter of the Next
                // function call by one, i.e. lastLeftGroupsOrderIdx + 1.
                if (_lastLeftGroupsOrderIdx == 0)
                    _nextLeftGroupsOrderIdx = 0;
                else
                    _nextLeftGroupsOrderIdx = random.Next(0,
                                                         _lastLeftGroupsOrderIdx);

                // Get the actual index of the character group, from which we will
                // pick the next character.
                _nextGroupIdx = _leftGroupsOrder[_nextLeftGroupsOrderIdx];

                // Get the index of the last unprocessed characters in this group.
                _lastCharIdx = _charsLeftInGroup[_nextGroupIdx] - 1;

                // If only one unprocessed character is left, pick it; otherwise,
                // get a random character from the unused character list.
                if (_lastCharIdx == 0)
                    _nextCharIdx = 0;
                else
                    _nextCharIdx = random.Next(0, _lastCharIdx + 1);

                // Add this character to the password.
                _verificationCode[i] = _charGroups[_nextGroupIdx][_nextCharIdx];

                // If we processed the last character in this group, start over.
                if (_lastCharIdx == 0)
                    _charsLeftInGroup[_nextGroupIdx] =
                                              _charGroups[_nextGroupIdx].Length;
                // There are more unprocessed characters left.
                else
                {
                    // Swap processed character with the last unprocessed character
                    // so that we don't pick it until we process all characters in
                    // this group.
                    if (_lastCharIdx != _nextCharIdx)
                    {
                        char _temp = _charGroups[_nextGroupIdx][_lastCharIdx];
                        _charGroups[_nextGroupIdx][_lastCharIdx] =
                                    _charGroups[_nextGroupIdx][_nextCharIdx];
                        _charGroups[_nextGroupIdx][_nextCharIdx] = _temp;
                    }
                    // Decrement the number of unprocessed characters in
                    // this group.
                    _charsLeftInGroup[_nextGroupIdx]--;
                }

                // If we processed the last group, start all over.
                if (_lastLeftGroupsOrderIdx == 0)
                    _lastLeftGroupsOrderIdx = _leftGroupsOrder.Length - 1;
                // There are more unprocessed groups left.
                else
                {
                    // Swap processed group with the last unprocessed group
                    // so that we don't pick it until we process all groups.
                    if (_lastLeftGroupsOrderIdx != _nextLeftGroupsOrderIdx)
                    {
                        int _temp = _leftGroupsOrder[_lastLeftGroupsOrderIdx];
                        _leftGroupsOrder[_lastLeftGroupsOrderIdx] =
                                    _leftGroupsOrder[_nextLeftGroupsOrderIdx];
                        _leftGroupsOrder[_nextLeftGroupsOrderIdx] = _temp;
                    }
                    // Decrement the number of unprocessed groups.
                    _lastLeftGroupsOrderIdx--;
                }
            }

            // Convert password characters into a string and return the result.
            return new string(_verificationCode);
        }

No comments: