为什么会有这种情况出现呢,都是因为M$公司开发的软件Excel,这个软件里面的单元格定位是采用类似地图标注的定位方式,横坐标是已英文A-Z26个字母的形式增长的,纵坐标是数字递增形式。于是就有了下面10进制转26进制的函数出现。
function dec2excel($num) {
$str = strtoupper(base_convert($num,10,26));
for($i=0;$i<strlen($str);$i++) {
$str{$i} = ord($str{$i}) < 58 ? chr(ord($str{$i}) +16) : chr(ord($str{$i}) + 10);
}
return $str;
}
PHP里面有提供一个base_convert函数,可以在任意进制之间进行转换。当然这个任意是有限度的,具体来说是在【2-36】之间。为什么是36呢?回头再讲。
但是这里有个问题,不管那种进制,第一个自然数都是1开头的,但是Excel里面的横坐标是以字母A开始的。于是就面临1-9要顺移到A-I的问题。这里1的ASCII值为49 A的ASCII值为65 所以简单判断ASCII值,小于58【9的ASCII值为57】的 递增16,否则递增10。但是这里出现了一个问题,0怎么处理?????这个函数没有对0进行处理,或者说0的处理是完全错误的,0的ASCII值为48,48+16 = 64 ,而ASCII码值为64的是@。
/**
* 自然数 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
* base_convert之后 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k m n o p q 10 11
* 实际的A-Z组成的26进制 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA
*/
看来这个函数不能这么搞。问题的关键就出在 自然数是[1-9]+0 而26进制是[A-Z]的循环。
难道要回归原始的根据每一位所代表的权重用计算的方式把A-Z的26进制弄出来?不行,再想办法。
今天回家的地铁里左思又想也得不到结果,有朋友推荐我去看Excel的相关函数,我想这么简单的东西,算我笨好了,一晚上总想得出来的吧。
终于被我想到了解决方法。我就用死算的方法好了:
function ori_dec2excel($num) {
$a = array('A','B','C','D',...,'T','U','V','W','X','Y','Z');
$yushu = $num % 26;
$jixuchuli = ($num - $yushu) / 26 ;
if($jixuchuli <= 26) {
return $a[$jixuchuli-1].$a[$yushu-1];
} else {
return ori_dec2excel($jixuchuli).$a[$yushu-1];
}
}
但是下面这个表达式的结果确不是我想要的,52的26进制应该是AZ。 用base_convert的方式表达是20。
$k = ori_dec2excel(52);
问题的关键就出在A-Z之中没有“0”。
或者说按照上面的函数 $num % 26 之后,如果余数为0的话,要把这个26给退回来,不能放到高权重的位去处理。于是最后的解决方式出笼了。
function ori_dec2excel($num) {
$a = array('A','B','C','D','E',...,'V','W','X','Y','Z');
$yushu = $num % 26;
$yushu = $yushu == 0 ? 26:$yushu;
$jixuchuli = ($num - $yushu) / 26 ;
if($jixuchuli <= 26) {
return $a[$jixuchuli-1].$a[$yushu-1];
} else {
return ori_dec2excel($jixuchuli).$a[$yushu-1];
}
}
最后附上我的26进制转10进制的函数,这个的思路就比10进制转26进制要简单的多了。
function ori_excel2dec($num) {
$v=0;
$l = strlen($num);
$a = array('A','B','C','D','E',...,'U','V','W','X','Y','Z');
for($i=0;$i<$l;$i++) {
$v += (array_search($num{$i},$a)+1)*pow(26,($l-$i-1))."\r\n";
}
return $v;
}
为什么PHP的base_convert最大只提供到36进制的转换呢,那是因为:0-9 十个数字加上 a-z 26个字母,可以用来表达不同位的字符只有36个。所以,这下明白了吧。