我正在创建一个将数字转换为具有预定义字符的字符串的函数。原来,我知道。我开始了,因为当时看起来很有趣。我自己做。嗯,这很令人沮丧而且不好玩。
我希望它像二进制一样,因为任何左边的角色都比它的右边界更有价值。二进制是低效的,因为每个位只有1个正值。 Xnary是有效的,因为'bit'永远不会为0。
字符集(在本例中):A - Z
。
A = 1 ..
Z = 26
AA = 27 ..
AZ = 52
BA = 53 ..
BZ = 2 * 26 (B) + 26 * 1 (Z) = 78... Right?
ZZ = 26 * 26 (Z) + 26 * 1 (Z) = 702?? Right??
我找到this here,但AA
与A
和AAA
相同。该函数的结果绝不是AA
或AAA
。
字符串A
与AA
和AAA
不同,因此数字也应该不同。 (与二进制文件1
,01
,001
等不同。)因为较长的字符串总是比较短的字符串更有价值... A < AA < AAA
。
这有意义吗?我之前试图解释它并且失败了。我之前也尝试过。 =)
最重要的是:自A < AA < AAA
以来,'my'ABC
的值高于其他脚本的值。另一个区别是:我的脚本不存在,因为我一直都在失败。
我尝试过this algorithm:
N = 1000, Size = 3, (because 26 log(1000) = 2.x), so use 676, 26 and 1 for positions:
N = 1000
P0 = 1000 / 676 = 1.x = 1 = A
N = 1000 - 1 * 676 = 324
P1 = 324 / 26 = 12.x = 12 = L
N = 324 - 12 * 26 = 12
P1 = 12 / 1 = 12 = L
1000 => ALL
听起来很公平?显然这是废话。这是因为:
N = 158760, Size = 4, so use 17576, 676, 26 and 1
P0 = 158760 / 17576 = 9.x = 9 = I
N = 158760 - 9 * 17576 = 576
P1 = 576 / 676 = 0.x = 0 <<< OOPS
如果1
是A
(xnary的第一个),那么0
是什么?不可能就是它。
所以这个是一个半身像。另一个(on jsFiddle)也是一个半身像,因为A != AA != AAA
这是事实。
那么我在几个漫长的夜晚失踪了什么?
哦,顺便说一句:如果你不喜欢数字,请不要读这个。
PS。我试过寻找类似的问题,但没有一个相似。一个参考文献最相似,但是'错误'的IMO。
答案 0 :(得分:4)
也称为Excel列编号。如果我们换一个A = 0, ..., Z = 25, AA = 26, ...
,至少在计算中更容易。对于你的方案,所有需要的是在转换为Xnary resp之前减1。转换后的加法。
所以,通过这种修改,让我们开始寻找转换。首先,我们需要多少个符号来编码n
?那么,有26个一位数字,26 ^ 2个两位数字,26 ^ 3个三位数字等。因此,使用最多d
个数字的数字总数为26^1 + 26^2 + ... + 26^d
。这是几何系列的开始,我们知道总和的封闭形式26*(26^d - 1)/(26-1)
。因此要对n
进行编码,我们需要d
个数字,如果
26*(26^(d-1)-1)/25 <= n < 26*(26^d-1)/25 // remember, A = 0 takes one 'digit'
或
26^(d-1) <= (25*n)/26 + 1 < 26^d
也就是说,我们需要d(n) = floor(log_26(25*n/26+1)) + 1
个数字来编码n >= 0
。现在,我们必须减去最多需要d(n) - 1
个数字的总数才能找到n
个数字中d(n)
的位置,我们称之为p(n) = n - 26*(26^(d(n)-1)-1)/25
。而n
的编码只是d(n)
- 数字基数为26的p(n)
编码。
另一个方向的转换是基数为26的扩展,然后是26*(26^(d-1) - 1)/25
的加法。
因此对于N = 1000
,我们编码n = 999
,log_26(25*999/26+1) = log_26(961.5769...) = 2.x
,我们需要3位数。
p(999) = 999 - 702 = 297
297 = 0*26^2 + 11*26 + 11
999 = ALL
对于N = 158760
,n = 158759
和log_26(25*158759/26+1) = 3.66...
,我们需要四位数
p(158759) = 158759 - 18278 = 140481
140481 = 7*26^3 + 25*26^2 + 21*26 + 3
158759 = H Z V D
答案 1 :(得分:2)
这似乎是一个非常标准的“从基数10到基数N的实现转换”,其中N恰好是26,并且您使用字母来表示所有数字。
如果您将A-Z作为26ary值,则可以表示0到(26 - 1)(就像二进制可以表示0 - (2 - 1)。
BZ = 1 * 26 + 25 * 1 = 51
类似物将是:
19 = 1 * 10 + 9 * 1(1 / B是第一个非零字符,9 / Z是可能的最大数字)。
你基本上有正确的想法,但是你需要改变它,所以A = 0,而不是A = 1.那么一切都应该相对合理。
答案 2 :(得分:0)
在@Daniel的冗长答案中,我看到了log()
的号召,这是表演的红旗。这是一种没有太多复杂数学的简单方法:
function excelize(colNum) {
var order = 0, sub = 0, divTmp = colNum;
do {
divTmp -= 26**order;
sub += 26**order;
divTmp = (divTmp - (divTmp % 26)) / 26;
order++;
} while(divTmp > 0);
var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
var tr = c => symbols[symbols.indexOf(c)+10];
Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
}
说明:
由于这不是base26,我们需要减去每个附加符号的基本时间顺序(&#34;数字&#34;)。所以首先我们计算结果数的顺序,同时计算子数。然后我们将其转换为基数26并将其减去,然后将符号移至A-Z
而不是0-P
。