Return a new string that sorts between two given strings
Created on 2024-04-22T18:03:26-05:00
Algorithm
Assumes an alphabet of a-z, and that spaces ' ' sort before 'a'.
- Copy characters from the beginning of both strings until you reach the first difference or end of left string.
- Append character half way between left character (or alphabet beginning) and the right character.
- If the characters are consecutive: copy left character, then append character half way between next on left string and end of the alphabet.
- If the next character on the left is one or more Zs, copy and append character between first on-z and end of alphabet.
- Never create a string by appending A to the left. If you end up doing this, add an additional character half way between the start of alphabet and next character from right string.
Code
int midstring(const char *prev, const char *next, char *buf) { char p = 0, n = 0; int len = 0; while (p == n) { // copy identical part p = prev[len] ? prev[len] : 'a' - 1; n = next[len] ? next[len] : 'z' + 1; if (p == n) buf[len++] = p; } if (p == 'a' - 1) { // end of left string while (n == 'a') { // handle a's buf[len++] = 'a'; n = next[len] ? next[len] : 'z' + 1; } if (n == 'b') { // handle b buf[len++] = 'a'; n = 'z' + 1; } } else if (p + 1 == n) { // consecutive characters n = 'z' + 1; buf[len++] = p; while ((p = prev[len] ? prev[len] : 'a' - 1) == 'z') { // handle z's buf[len++] = 'z'; } } buf[len++] = n - (n - p) / 2; // append middle character buf[len] = '\0'; return len; }
Code for renumbering strings
Generate a set of average length strings, after you've screwed up your namespace with long strings.
function seqString(num) { var chars = Math.floor(Math.log(num) / Math.log(26)) + 1; var prev = Math.pow(26, chars - 1); var ratio = chars > 1 ? (num + 1 - prev) / prev : num; var part = Math.floor(ratio); var alpha = [partialAlphabet(part), partialAlphabet(part + 1)]; var leap_step = ratio % 1, leap_total = 0.5; var first = true; var strings = []; generateStrings(chars - 1, ""); return strings; function generateStrings(full, str) { if (full) { for (var i = 0; i < 26; i++) { generateStrings(full - 1, str + String.fromCharCode(97 + i)); } } else { if (!first) strings.push(stripTrailingAs(str)); else first = false; var leap = Math.floor(leap_total += leap_step); leap_total %= 1; for (var i = 0; i < part + leap; i++) { strings.push(str + alpha[leap][i]); } } } function stripTrailingAs(str) { var last = str.length - 1; while (str.charAt(last) == 'a') --last; return str.slice(0, last + 1); } function partialAlphabet(num) { var magic = [0, 4096, 65792, 528416, 1081872, 2167048, 2376776, 4756004, 4794660, 5411476, 9775442, 11097386, 11184810, 22369621]; var bits = num < 13 ? magic[num] : 33554431 - magic[25 - num]; var chars = []; for (var i = 1; i < 26; i++, bits >>= 1) { if (bits & 1) chars.push(String.fromCharCode(97 + i)); } return chars; } } document.write(seqString(1600).join(' '));