Skip to content

Instantly share code, notes, and snippets.

@vicomte
Forked from devongovett/succ.js
Last active December 21, 2015 15:09
Show Gist options
  • Save vicomte/6324231 to your computer and use it in GitHub Desktop.
Save vicomte/6324231 to your computer and use it in GitHub Desktop.
/*
* An implementation of Ruby's string.succ method.
* By Devon Govett
*
* Returns the successor to str. The successor is calculated by incrementing characters starting
* from the rightmost alphanumeric (or the rightmost character if there are no alphanumerics) in the
* string. Incrementing a digit always results in another digit, and incrementing a letter results in
* another letter of the same case.
*
* If the increment generates a carry, the character to the left of it is incremented. This
* process repeats until there is no carry, adding an additional character if necessary.
*
* succ("abcd") == "abce"
* succ("THX1138") == "THX1139"
* succ("<<koala>>") == "<<koalb>>"
* succ("1999zzz") == "2000aaa"
* succ("ZZZ9999") == "AAAA0000"
*
* if strictSeparators is true, any carry operation works only on the segment within
* the bounds of a non alphanumeric character, or alternating type. Defaults to adding
* a numeric if it can't find any.
*
* succ("aaa-999", true) == "aaa-1000"
* succ("234zzz", true) == "234aaaa"
*
*/
function succ(input,strictSeparators) {
var alphabet = 'abcdefghijklmnopqrstuvwxyz';
if (input.length < 2 && !input.match(/\w/)) {
result = input + alphabet.charAt(0);
} else {
if (input.length > 1
&& typeof strictSeparators !== 'undefined'
&& strictSeparators === true) {
allAlphas = input.match(/[a-z0-9]/i);
var lastChar = input.substring(input.lastIndexOf(allAlphas[allAlphas.length - 1])+1,1);
if (lastChar.match(/[a-z]/i)) {
regex = /[^A-Za-z]/g;
} else {
regex = /\D/g;
}
var segments = input.match(regex);
if (segments) {
rIndex = input.lastIndexOf(segments[segments.length - 1]);
if (rIndex != 'undefined' && rIndex >= 0) {
var origString = input;
input = input.substring(rIndex + 1);
origString = origString.substring(0,rIndex + 1);
}
}
}
var length = alphabet.length,
result = input,
i = input.length;
while(i >= 0) {
var last = input.charAt(--i),
next = '',
carry = false;
if (isNaN(last)) {
index = alphabet.indexOf(last.toLowerCase());
if (index === -1) {
next = last;
carry = true;
}
else {
var isUpperCase = last === last.toUpperCase();
next = alphabet.charAt((index + 1) % length);
if (isUpperCase) {
next = next.toUpperCase();
}
carry = index + 1 >= length;
if (carry && i === 0) {
var added = isUpperCase ? 'A' : 'a';
result = added + next + result.slice(1);
break;
}
}
}
else {
next = +last + 1;
if(next > 9 && !strictSeparators) {
next = 0;
carry = true;
}
if (carry && i === 0) {
result = '1' + next + result.slice(1);
break;
}
}
result = result.slice(0, i) + next + result.slice(i + 1);
if (!carry) {
break;
}
}
}
if (typeof origString !== 'undefined' && origString.length > 0) {
result = origString + result;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment