Reputation: 1558
I want to create a userfriendly system to make users enter a certain id:
id 1-26: A-Z
27: AA
28: AB
...
...
ZZZ
I tried several ways to achieve this but I get random characters...
$counter = 7;
do {
$temp = floor($id / (26^$counter)) % 26;
$counter--;
echo($temp.' ');
} while($counter > 0);
Upvotes: 0
Views: 84
Reputation: 6849
This is a base-converting problem, but there's a little trick.
First we consider 'A'
as 1
, so 'AA'
or 'AAA'
could make sense, and 'B'
as 2
, 'C'
as 3
.., but what about 'Z'
? No, 'Z'
is not 26, the trick here is to consider the 'Z'
as 'A0'
, and every time we find a 0
when in converting, we write it down as 'Z'
, and throw a 'A'
away(by subtracting 1).
so we have the following code:
function num2user( $num )
{
$s = "ZABCDEFGHIJKLMNOPQRSTUVWXYZ";
$ret = "";
while( $num > 0 )
{
$m = $num % 26;
$ret = $s[$m].$ret;
$num = floor($num / 26);
if( $m == 0 ) $num = $num - 1;
}
return $ret;
}
for( $i = 1 ; $i < 128 ; $i++ )
{
echo "$i=".num2user($i)."\n";
}
Upvotes: 0
Reputation: 10080
Mapping Excel column name to numeric order is kind of a crappy thing, because there's no 0
in A-Z...
Anyway, I did come up with two functions to convert them back and forth:
function calcCol($col) //character to number
{
if(is_numeric($col)) return intval($col);
$col=array_reverse(str_split(strtoupper(preg_replace("/[^a-z]/i","",$col))));
$num=0;
foreach($col as $i=>$ch)
{
$num+=(ord($ch)-ord('A')+1)*pow(27,$i);
}
$num-=ceil($num/27)-1;
return $num;
}
function getCol($col) //number to character
{
if(preg_match("/^[a-z]+$/i",$col)) return strtoupper($col);
$col=abs(intval($col));
$col+=ceil($col/26)-1;
$str="";
while($col>0)
{
$tmp=$col%27;
$str=chr($tmp-1+ord('A')).$str;
$col=floor($col/27);
}
return $str;
}
Explanation:
Consider A-Z as a 27-based numeric system with a missing/hidden 0
;
And after converting from character to number, removes those hidden 0
s by counting how many 27 is "counted" (ceil($num/27)
);
And before converting from number to character, add those hidden 0
s back by counting how many 26 is "counted" (ceil($col/26)
).
Upvotes: 1