如何创建一个将数字转换为双向Hexavigesimal的函数?

时间:2011-12-22 11:50:20

标签: javascript excel hexavigesimal

也许我在数学方面还不够好,但我在将数字转换为纯字母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;
    }

我努力的最佳结果是:a b c d ... y z ba bb bc - 虽然不是上面的实际代码。预期输出为a b c ... y z aa ab ac ... zz aaa aab aac ... zzzzz aaaaaa aaaaab,您可以得到图片。

基本上,我的问题更多的是做''数学'而不是功能。最后我的问题是:如何在Hexavigesimal转换中进行数学运算,直到[假设]无穷大,就像Microsoft Excel一样。

如果可能,请提供源代码,提前谢谢。

6 个答案:

答案 0 :(得分:13)

好的,这是我的尝试,假设您希望序列以“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;
}

但是,如果您打算按顺序打印出来,那么有更有效的方法。例如,使用递归和/或前缀和东西。

答案 1 :(得分:3)

虽然@ 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"

答案 2 :(得分:0)

我不明白如何从公式中解决这个问题,但我愚弄了一段时间,并提出了以下算法来计算所需的列号:

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的值。

答案 3 :(得分:0)

今晚早些时候刚刚完成了this code的写作,我在寻找这个该死的东西的过程中找到了这个问题。这是(如果有人觉得使用它):

/**
 * Convert an integer to bijective hexavigesimal notation (alphabetic base-26).
 *
 * @param {Number} int - A positive integer above zero
 * @return {String} The number's 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("")
}

答案 4 :(得分:0)

您可以通过递归来完成此操作,如下所示:

const toBijective = n => (n > 26 ? toBijective(Math.floor((n - 1) / 26)) : "") + ((n % 26 || 26) + 9).toString(36);
// Parsing is not recursive
const parseBijective = str => str.split("").reverse().reduce((acc, x, i) => acc + ((parseInt(x, 36) - 9) * (26 ** i)), 0);

toBijective(1) // "a"
toBijective(27) // "aa"
toBijective(703) // "aaa"
toBijective(18279) // "aaaa"
toBijective(127341046141) // "overflow"

parseBijective("Overflow") // 127341046141

答案 5 :(得分:-3)

a代表0z代表25。因此,z之后的数字为26,即1*26 + 0,因此ba是正确的。 (而zzzzz之后的数字是baaaaa。)