Ferdau
Ferdau

Reputation: 1558

Id to userfriendly characters

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

Answers (2)

Marcus
Marcus

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

Passerby
Passerby

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 0s by counting how many 27 is "counted" (ceil($num/27));

And before converting from number to character, add those hidden 0s back by counting how many 26 is "counted" (ceil($col/26)).

Upvotes: 1

Related Questions