7

也许我在数学方面还不够好,但我在将数字转换为纯字母双射十六进制时遇到了问题,就像Microsoft Excel/OpenOffice Calc 所做的那样。

这是我的代码的一个版本,但没有给我所需的输出:

    var toHexvg = 函数(a){
     变量 x='';
     var let="_abcdefghijklmnopqrstuvwxyz";
     var len=let.length;
     变量 b=a;
     变量cnt = 0;
     变量 y = 数组();
     做{
      a=(a-(a%len))/len;
      cnt++;
     }while(a!=0)
     a=b;
     var vnt=0;
     做{
      b+=Math.pow((len),vnt)*Math.floor(a/Math.pow((len),vnt+1));
      vnt++;
     }while(vnt!=cnt)
     变量 c=b;
     做{
      y.unshift(c%len);
      c=(c-(c%len))/len;
     }while(c!=0)
     for(var i in y)x+=let[y[i]];
     返回 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,你得到了图片。

基本上,我的问题更多是在做“数学”而不是函数。最终我的问题是:如何在十六进制转换中进行数学运算,直到 [supposed] 无穷大,就像 Microsoft Excel 一样。

如果可能的话,一个源代码,提前谢谢你。

4

7 回答 7

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;
}

但是,如果您打算简单地将它们按顺序打印出来,那么还有更有效的方法。例如,使用递归和/或前缀等。

于 2011-12-22T13:31:52.387 回答
3

尽管@user826788 已经发布了一个工作代码(甚至快了三分之一),但我会发布我自己的工作,这是我在在这里找到帖子之前所做的(因为我不知道“十六进制”这个词)。但是,它还包括反之亦然的功能。请注意,我使用 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"
于 2012-07-16T14:05:21.993 回答
2

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

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
于 2019-05-09T02:44:47.210 回答
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)和计算第 10,000,000 个值 ( ) 大约需要 20 秒uvxxk。移除缓存后,第 10,000,000 个值大约需要 14 秒。

于 2011-12-22T13:37:43.967 回答
0

今晚早些时候刚写完这段代码,我在寻找这个该死的东西的名字时发现了这个问题。在这里(以防有人喜欢使用它):

/**
 * 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("")
}
于 2016-01-17T14:23:01.990 回答
0

我今天必须解决同样的问题才能工作。我的解决方案是用 Elixir 编写的并使用递归,但我用简单的英语解释了这个想法。

以下是一些示例转换:

0 ->“A”,1 ->“B”,2 ->“C”,3 ->“D”,.. 25 ->“Z”,26 ->“AA”,27 ->“AB” , ...

乍一看,这似乎是一个普通的 26 碱基计数系统,但不幸的是,它并不是那么简单。当您意识到:

A = 0
AA = 26

这与正常的计数系统不一致,其中“0”在除该单位以外的小数位时不会表现为“1”。

要理解该算法,请考虑一个更简单但等效的 base-2 系统:

A = 0
B = 1
AA = 2
AB = 3
BA = 4
BB = 5
AAA = 6

在正常的二进制计数系统中,我们可以通过增加 2(1、2、4、8、16)的幂来确定小数位的“值”,并且二进制数的值是通过将每个数字乘以该数字的位置来计算的价值。例如 10101 = 1 * (2 ^ 4) + 0 * (2 ^ 3) + 1 * (2 ^ 2) + 0 * (2 ^ 1) + 1 * (2 ^ 0) = 21

在我们更复杂的 AB 系统中,我们可以通过检查看到小数位值是:

1, 2, 6, 14, 30, 62

该模式显示自己是(previous_unit_place_value + 1) * 2。因此,为了获得下一个较低的单位位值,我们除以 2 并减去 1。

这可以扩展到 base-26 系统。只需除以 26 并减去 1。

现在,将普通的以 10 为基数的数字转换为特殊的以 26 为基数的公式是显而易见的。说输入是x.

  1. 创建一个累加器列表l
  2. 如果 x 小于 26,则设置l = [x | l]并转到步骤 5。否则,继续。
  3. 将 x 除以 2。取底结果为d,余数为r
  4. 将剩余部分作为累加器列表的头部。IEl = [r | l]
  5. 以 (d - 1) 作为输入,转到第 2 步,例如x = d - 1
  6. 将 """ 的所有元素转换l为其对应的字符。0 -> A 等。

所以,最后,这是我用 Elixir 写的答案:

defmodule BijectiveHexavigesimal do
  def to_az_string(number, base \\ 26) do
    number
    |> to_list(base)
    |> Enum.map(&to_char/1)
    |> to_string()
  end

  def to_09_integer(string, base \\ 26) do
    string
    |> String.to_charlist()
    |> Enum.reverse()
    |> Enum.reduce({0, nil}, fn
      char, {_total, nil} ->
        {to_integer(char), 1}

      char, {total, previous_place_value} ->
        char_value = to_integer(char + 1)
        place_value = previous_place_value * base
        new_total = total + char_value * place_value
        {new_total, place_value}
    end)
    |> elem(0)
  end

  def to_list(number, base, acc \\ []) do
    if number < base do
      [number | acc]
    else
      to_list(div(number, base) - 1, base, [rem(number, base) | acc])
    end
  end

  defp to_char(x), do: x + 65
end

您只需将其用作BijectiveHexavigesimal.to_az_string(420). 它还接受可选的“基本”参数。

我知道 OP 询问了 Javascript,但我想为后代提供 Elixir 解决方案。

于 2022-02-25T04:53:02.860 回答
-2

a代表0z代表25。所以后面的数字z26,即1*26 + 0,所以ba是正确的。(后面的数字zzzzzbaaaaa。)

于 2011-12-22T11:56:19.580 回答