Как создать функцию, которая преобразует число в биективный шестнадцатеричный?

Может быть, я просто недостаточно хорош в математике, но у меня возникла проблема с преобразованием числа в чистый алфавитный Bijective Hexavigesimal, как это делает Microsoft Excel/OpenOffice Calc.

Вот версия моего кода, но не предоставила мне результат, который мне нужен:

var toHexvg = function(a){ var x=''; var let="_abcdefghijklmnopqrstuvwxyz"; var len=let.length; var b=a; var cnt=0; var y = Array(); do{ a=(a-(a%len))/len; cnt++; }while(a!=0) a=b; var vnt=0; do{ b+=Math.pow((len),vnt)*Math.floor(a/Math.pow((len),vnt+1)); vnt++; }while(vnt!=cnt) var c=b; do{ y.unshift( c%len ); c=(c-(c%len))/len; }while(c!=0) for(var i in y)x+=let[y[i]]; return x; }

Наилучшим результатом моих усилий может стать: abcd... yz ba bb bc - хотя и не фактический код выше. Предполагаемый вывод - это abc... yz aa ab ac... zz aaa aab aac... zzzzz aaaaaa aaaaab, вы получите картину.

В основном, моя проблема связана скорее с выполнением "математики", а не с функцией. В конечном счете, мой вопрос: как сделать математику в шестнадцатеричном преобразовании, до [предполагаемой] бесконечности, как и Microsoft Excel.

И если это возможно, исходный код, спасибо заранее.

5 ответов

Хорошо, вот моя попытка, предполагая, что вы хотите, чтобы последовательность начиналась с "a" (представляющая 0) и переходила:

a, b, c, ..., y, z, aa, ab, ac, ..., zy, zz, aaa, aab, ...

Это работает и, надеюсь, имеет смысл. Фанковая линия есть потому, что математически имеет смысл, чтобы 0 представлялось пустой строкой, а затем "a" было бы равно 1 и т.д.

alpha = "abcdefghijklmnopqrstuvwxyz";
function hex(a) { // First figure out how many digits there are. a += 1; // This line is funky c = 0; var x = 1; while (a >= x) { c++; a -= x; x *= 26; } // Now you can do normal base conversion. var s = ""; for (var i = 0; i < c; i++) { s = alpha.charAt(a % 26) + s; a = Math.floor(a/26); } return s;
}

Однако, если вы планируете просто распечатать их по порядку, есть гораздо более эффективные методы. Например, используя рекурсию и/или префиксы и прочее.


Хотя @user826788 уже опубликовал рабочий код (который даже третий быстрее), я опубликую свою собственную работу, которую я сделал, прежде чем найти сообщения здесь (так как я не знал слово "hexavigesimal"). Однако он также включает функцию для другого. Обратите внимание, что я использую a = 1, поскольку я использую его для преобразования элемента начального списка из

aa) first
ab) second

в

<ol type="a" start="27">
<li>first</li>
<li>second</li>
</ol>

:

function linum2int(input) { input = input.replace(/[^A-Za-z]/, ''); output = 0; for (i = 0; i < input.length; i++) { output = output * 26 + parseInt(input.substr(i, 1), 26 + 10) - 9; } console.log('linum', output); return output;
}
function int2linum(input) { var zeros = 0; var next = input; var generation = 0; while (next >= 27) { next = (next - 1) / 26 - (next - 1) % 26 / 26; zeros += next * Math.pow(27, generation); generation++; } output = (input + zeros).toString(27).replace(/./g, function ($0) { return '_abcdefghijklmnopqrstuvwxyz'.charAt(parseInt($0, 27)); }); return output;
}
linum2int("aa"); // 27
int2linum(27); // "aa"


Только что закончил писать этот код ранее сегодня вечером, и я нашел этот вопрос, пока на поиски, чтобы выяснить, как назвать эту чертову вещь. Вот он (в случае, если кто-то хочет его использовать):

/** * Convert an integer to bijective hexavigesimal notation (alphabetic base-26). * * @param {Number} int - A positive integer above zero * @return {String} The number value expressed in uppercased bijective base-26 */
function bijectiveBase26(int){ const sequence = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const length = sequence.length; if(int <= 0) return int; if(int <= length) return sequence[int - 1]; let index = (int % length) || length; let result = [sequence[index - 1]]; while((int = Math.floor((int - 1) / length)) > 0){ index = (int % length) || length; result.push(sequence[index - 1]); } return result.reverse().join("")
}


Я не понимаю, как это исправить из формулы, но я некоторое время обманывал ее и придумал следующий алгоритм, чтобы буквально подсчитать требуемый номер столбца:

var getAlpha = (function() { var alphas = [null, "a"], highest = [1]; return function(decNum) { if (alphas[decNum]) return alphas[decNum]; var d, next, carry, i = alphas.length; for(; i <= decNum; i++) { next = ""; carry = true; for(d = 0; d < highest.length; d++){ if (carry) { if (highest[d] === 26) { highest[d] = 1; } else { highest[d]++; carry = false; } } next = String.fromCharCode( highest[d] + 96) + next; } if (carry) { highest.push(1); next = "a" + next; } alphas[i] = next; } return alphas[decNum]; };
})();
alert(getAlpha(27)); // "aa"
alert(getAlpha(100000)); // "eqxd"

Демо: http://jsfiddle.net/6SE2f/1/

highest массив содержит текущее наибольшее число с элементом массива на "цифру" (элемент 0 является наименее значимой "цифрой").

Когда я начал использовать вышеизложенное, было бы неплохо кэшировать каждое значение после вычисления, чтобы сэкономить время, если одно и то же значение было запрошено снова, но на практике (с Chrome) потребовалось всего около 3 секунд для вычисления 1,000,000-го значения (bdwgn) и около 20 секунд для вычисления 10 000 000-й величины (uvxxk). С удалением кэширования потребовалось около 14 секунд для 10 000 000-го значения.


a представляет 0, а z представляет собой 25. Таким образом, число после z равно 26, что равно 1*26 + 0, поэтому ba является правильным. (И номер после zzzzz - baaaaa.)

licensed under cc by-sa 3.0 with attribution.