1

I want to generate a line of numbers and letters in this format using Javascript.

Example: F35-HE4E-WAD-32S

So a line of 3-4-3-3 of random numbers and letters.

3
  • 5
    What have you tried? And are there any restrictions on the values (e.g., must they be unique? Uppercase only, or mixed case allowed? Any requirements around number of letters or numbers in any or all of the groupings?). Commented Feb 10, 2015 at 20:02
  • related question on JavaScript GUIDs Commented Feb 10, 2015 at 20:05
  • Looking for uppercase only. I haven't tried anything yet, just researching to find the best possible way to generate the 3-4-3-3 line. I had thought about generating each line individually (3 then 4 then 3 ect.) and putting them together like that, but I'm sure there is a better way to do it. I'm not the best when it comes to scripting sadly. Commented Feb 10, 2015 at 20:08

3 Answers 3

4

I would make a function which generates a random sequence matching a given template. Something like this:

function getSequence(template) {
    var r = '', ch, n;
    for (var i = 0; i < template.length; i++) {
        ch = template.substr(i, 1);
        if (ch == "d") {
            r += parseInt(Math.random() * 10);
        } else if (ch == "A") {
            r += String.fromCharCode(65 + parseInt(Math.random() * 26));
        } else if (ch == "w") {
            n = parseInt(Math.random() * 36);
            if (n > 9) {
                r += String.fromCharCode(55 + n);
            } else {
                r += n;
            }
        } else {
            r += ch;
        }
    }
    return r;
}
console.log(getSequence('Add-wwww-AAA-ddA'));

http://jsfiddle.net/xpt9od7c/

In the example given 'A' is used for capital letters, 'd' for digits (numbers) and 'w' for either. So 'Add-wwww' will return a sequence of one capital letter, two numbers, a hyphen, then four characters that can be either letters or numbers. You can then adapt according to what kind of sequence you need.

EDIT. Perhaps a cleaner and more reusable implementation is to make a function that converts a template character into a random character picked from the corresponding character set, then call Array.map to apply that function to each character of the template string.

var CHAR_SETS = {
    d: '0123456789',
    A: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    w: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
};

function mapString(s, func) {
    return Array.prototype.map.call(s, func).join('')
}

function randChar(charType) {
    var chars = CHAR_SETS[charType];
    if (chars) {
        return chars.charAt(parseInt(Math.random() * chars.length));
    } else {
        return charType;
    }
}

console.log(mapString('Add-wwww-AAA-ddA', randChar));

http://jsfiddle.net/49hofey8/2/

Another option is to use replace:

var CHAR_SETS = {
    d: '0123456789',
    A: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
    w: '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
};

function randChar(charType) {
    var chars = CHAR_SETS[charType];
    return chars.charAt(parseInt(Math.random() * chars.length));
}
console.log('Add-wwww-AAA-ddA'.replace(/[Adw]/g, randChar));

http://jsfiddle.net/so3pf271/1/

Sign up to request clarification or add additional context in comments.

1 Comment

This concept is good, but again I would implement it using reusable functions.
2

A VERY simple way to do it would be to create an string of all of the characters that you want to include (digits and uppercase letters, in your case) and then use random number generation to pick which character to add from that string. You would then repeat this process with a loop . . . inserting dashes, where appropriate . . . until you had built out the string.

Something like this:

var sValidCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var sCharCode = "";

for (i = 0; i < 13; i++) {
    sCharCode = sCharCode + sValidCharacters.charAt(parseInt(Math.random() * sValidCharacters.length));

    if ((i === 2) || (i === 6) || (i === 9)) {
        sCharCode = sCharCode + "-";
    }
}

console.log(sCharCode);

The nice thing about this approach is that, since it uses the length of sValidCharacters when determining the random number, you can add or subtract valid characters from that "source string", without changing any of the code.

Some sample outputs from a few test runs:

HF1-EH46-RKP-8OL
VJ6-TRE1-DVA-WR7
156-ODA4-350-TP5
XBA-Q599-KZJ-FST
N82-DNM8-QSS-GUK

EDIT:

I took a second pass to make it a little more flexible, so that all you need to do is change parameters to generate the code of your choice. Here is the new "functionized" version:

function generateCode(sSourceCharacters, iCodeLength, sSeperator, aSeparatorPositions) {
    var sNewCode = "";

    for (i = 0; i < iCodeLength; i++) {
        sNewCode = sNewCode + sSourceCharacters.charAt(parseInt(Math.random() * sSourceCharacters.length));

        if (aSeparatorPositions.indexOf(i + 1) !== -1) {
            sNewCode = sNewCode + sSeperator;
        }
    }

    return sNewCode;
}

This way, you can pass in any parameters that you want, to generate a code, based on what you need. For your specific question, the options would be passed like this:

var charGroup = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var length = 13;
var divider = "-";
var dividerLocations = [3, 7, 10]; // the numbers indicate which character to place the divider after

var generatedCode = generateCode(charGroup, length, divider, dividerLocations);

But, you could also pass in something like:

var charGroup = "0123456789";
var length = 11;
var divider = ".";
var dividerLocations = [3, 6, 9];

. . . to get randomly generated IP addresses (though, in no way guaranteed to be valid :D ): Examples:

235.232.608.74
125.227.649.68
983.678.369.71
605.708.890.97
537.554.201.23

Or this, to generate a random, 4-letter, "encoded" swear word: :D

var charGroup = "!@#$%^&*()?";
var length = 4;
var divider = "";
var dividerLocations = [];

Results:

@%$%
)?$&
*&(!
!^@)
*))#

3 Comments

I have also used this principle, but more generically.
@Xotic750 - Yeah, I considered making it a little more parameter driven (key lengths, position of the "dashes", etc.), but decided to start with a simple answer first. I think I'll add a few more tweaks now. :)
@Xotic750 There . . . added some updates to give it a little more flexibility. :)
1

I would use something more generic.You can then reuse your functions for other code purposes.

Number.MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;

Number.MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER || -Number.MAX_SAFE_INTEGER;

Number.toInteger = Number.toInteger || function(inputArg) {
  var number = +inputArg,
    val = 0;

  if (number === number) {
    if (!number || number === Infinity || number === -Infinity) {
      val = number;
    } else {
      val = (number > 0 || -1) * Math.floor(Math.abs(number));
    }
  }

  return val;
};

function clampSafeInt(number) {
  return Math.min(Math.max(Number.toInteger(number), Number.MIN_SAFE_INTEGER), Number.MAX_SAFE_INTEGER);
}

Array.isArray = Array.isArray || function(inputArg) {
  return {}.toString.call(inputArg) === '[object Array]';
}

function isString(inputArg) {
  return {}.toString.call(inputArg) === '[object String]';
}

function generateChars(first, last) {
  first = isString(first) && first.length ? first.charCodeAt(0) : 0;
  last = isString(last) && last.length ? last.charCodeAt(0) : 0;

  var chars = [],
    index;

  for (index = first; index <= last; index += 1) {
    chars.push(String.fromCharCode(index));
  }

  return chars;
}

function randomInt(min, max) {
  var tmp,
    val;

  if (arguments.length === 1) {
    max = min;
    min = 0;
  }

  min = clampSafeInt(min);
  max = clampSafeInt(max);
  if (min > max) {
    tmp = min;
    min = max;
    max = tmp;
  }

  tmp = max - min + 1;
  if (tmp > Number.MAX_SAFE_INTEGER) {
    throw new RangeError('Difference of max and min is greater than Number.MAX_SAFE_INTEGER: ' + tmp);
  } else {
    val = Math.floor(Math.random() * tmp) + min;
  }

  return val;
}

function stringFromPool(ary, howMany) {
  var str = '';

  if (Array.isArray(ary)) {
    for (index = 0, howMany = Number.toInteger(howMany); index < howMany; index += 1) {
      str += ary[randomInt(ary.length - 1)];
    }
  }

  return str;
}

var getSequence = (function() {
  var lower = generateChars('a', 'z'),
    upper = generateChars('A', 'Z'),
    digit = generateChars('0', '9'),
    lowerDigit = lower.concat(digit),
    upperDigit = upper.concat(digit),
    all = lower.concat(upper, digit);

  return function(template) {
    var str = '',
      index,
      length,
      chr;

    if (isString(template) && template.length) {
      for (index = 0, length = template.length; index < length; index += 1) {
        chr = template.charAt(index);
        switch (chr) {
          case 'a':
            str += stringFromPool(lower, 1);
            break;
          case 'A':
            str += stringFromPool(upper, 1);
            break;
          case 'd':
            str += stringFromPool(digit, 1);
            break;
          case 'c':
            str += stringFromPool(lowerDigit, 1);
            break;
          case 'C':
            str += stringFromPool(upperDigit, 1);
            break;
          case 'x':
            str += stringFromPool(all, 1);
            break;
          default:
            str += chr;
        }
      }
    }

    return str;
  };
}());

function generatePattern() {
  return getSequence('CCC-CCCC-CCC-CCC');
}

function runMaxTimes(fn, howMany) {
  howMany = Number.toInteger(howMany);

  var count = 0;

  return function() {
    if (count < howMany) {
      count += 1;

      return fn.apply(this, arguments);
    }
  };
}

document.getElementById('generate').addEventListener('click', runMaxTimes(function(e) {
  this.textContent += generatePattern() + '\n';
}, 5).bind(document.getElementById('out')), false);
<button id="generate">Generate</button>
<pre id="out"></pre>

10 Comments

This is exactly what I was looking for. Thank you so much Xotic. Is there anyway to cap the number of possible generations to say 5? If it's too much of a hassle don't worry about it. Just trying to learn as much as possible.
Cap the generations where? I'm sure whatever you are thinking of is highly possible.
That now limits the generations to 5 times.
Ah sorry, I didn't make that clear. I'm pretty new to stackoverflow. I meant capping the number of possible generations to 5 instead of infinite if that makes sense?
Don't forget to take the tour: stackoverflow.com/tour and read the help: stackoverflow.com/help Your question is open to down votes and being closed.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.