Skip to content

Instantly share code, notes, and snippets.

@julesfern
Created June 20, 2011 18:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save julesfern/1036269 to your computer and use it in GitHub Desktop.
Save julesfern/1036269 to your computer and use it in GitHub Desktop.
A bit of fun for SpahQL.js - Matching ruby's range operations for strings in Javascript.
evalStringRange: function(start, end) {
var results = [];
// Figure out if this is a reversed or symmetrical range.
// Another easy comparison: Symmetrical ranges have one entry
if(start == end) return [start];
// Easy comparison: One string is shorter than the other or the range is reversed
if((start > end)||(start.length!=end.length)) return results;
// Columnar charcode indexes:
// integer: 48..57 == "0".."9"
// ucase: 65..90 == "A".."Z"
// lcase: 97..122 == "a".."z"
// We're going to treat this like a slot machine.
// Create an array of "locks" which are locked columns in the range.
var locks = [];
var allLocked = true;
for(var c=0; c<start.length; c++) {
var code = start.charCodeAt(c);
// If outside of range, lock
locks[c] = ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122))? false : true;
allLocked = (locks[c]==true && allLocked==true);
// If all others are locked and this is last column, unlock
if(allLocked && c == start.length-1) locks[c] = false;
}
var nextWorkingCol = function(wC) {
for(var w=wC-1; w>-2; w--) {
if(locks[w] == false) return w;
}
}
var gen = start+""; // clone start
iterating: while(true) {
// ^^^^
// When the workingCol hits -1 we know we popped a carry on the highest-order digit and maxed the string
// If nextString == end then we hit the range target and should break.
// Push the last-iterated result
//results.push(new Spah.SpahQL.QueryResult(null, gen));
results.push(gen);
if(gen == end) break iterating;
// Iterate until carrying stops, giving us our new stop value for the next increment
var workingCol = nextWorkingCol(start.length),
carry = true,
next = "";
carrying: while(true) {
// Iterate start string and push new results. Break on maxing all unlocked columns or on reaching end token.
// Iteration works on the lowest-order unlocked column and may generate a carry operation, which resets the current working
// column to its lowest value and increments the next highest-order unlocked column. This in turn may generate a carry operation.
// If the overall highest-order unlocked column generates a carry when incremented, then the string is maxed and the range
// terminates.
next = (function(str) {
// Iterates a character and generates a new string and potentially a carry.
var carry = false;
var cCode = str.charCodeAt(0);
var nCode;
if(cCode == 57) {
carry = true;
nCode = 48;
}
else if(cCode == 90) {
carry = true;
nCode = 65;
}
else if(cCode == 122) {
carry = true;
nCode = 97;
}
else if(cCode == 127) {
carry = true;
nCode = cCode;
}
else {
nCode = cCode+1;
}
return [String.fromCharCode(nCode), carry];
})(gen.charAt(workingCol));
gen = gen.split(""); gen.splice(workingCol,1,next[0]); gen = gen.join("");
if(next[1]==true) {
// Next next highest-order unlocked col
workingCol = nextWorkingCol(workingCol);
if(workingCol < 0) break iterating;
}
else {
break carrying;
}
}
}
return results;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment