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

Может быть, я просто недостаточно хорош в математике, но у меня возникла проблема с преобразованием числа в чистый алфавитный 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.