10

I know how to list from A to Z:

foreach (range('A', 'Z') as $char) {
  echo $char . "\n";
}

But how do I go on from there to list AA, AB, AC, AD, ... AZ, BA, BB, BC and so on?

I did a quick Google search and couldn't find anything, though I guess the approach will be different.

I think I can do it by using a for loop and an array with the letters inside, though that way seems a bit uncouth.

Any other way?

Thanks.

Lucas
  • 16,930
  • 31
  • 110
  • 182

6 Answers6

25

PHP has the string increment operator that does exactly that:

for($x = 'A'; $x < 'ZZ'; $x++)
    echo $x, ' ';

Result:

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 AB AC AD AE AF... 

Ref:

PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into '[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.

http://php.net/manual/en/language.operators.increment.php

georg
  • 211,518
  • 52
  • 313
  • 390
  • have to say, it works fine for the above case, but when you try to use `for ($x = 'A'; $x < 'AZ'; $x++)` for example, it breaks. – Lucas Sep 21 '14 at 11:14
  • 1
    @think123: just replace `<` with `!=` – georg Sep 21 '14 at 11:15
  • Not sure why setting `<=` does not work expectedly, there are many more results printed. Anyway we have to print the last `ZZ` if using `<`. – King King Sep 21 '14 at 11:23
  • @KingKing `<=` works exactly as expected, because you're comparing __alphabetically__ (like in a dictionary), and `B` comes ___after___ `AZ` in the dictionary.... if you need to print the last `ZZ`, then you compare `!== 'AAA'` – Mark Baker Sep 21 '14 at 11:38
  • @MarkBaker not sure what exactly the code you tried but if replacing the `<` with `<=` (from the code above) does not work for me (as I said it prints many more results than expected). Demo here http://3v4l.org/ko2ve – King King Sep 21 '14 at 12:32
  • 1
    I didn't try any code, I know how it works, I've answered this question many times over, and use this type of character incrementing in real code on an almost daily basis..... I'm telling you __not__ to use `<`, `<=`, `>` or `>=` with alphabetic comparisons like this, but ___always___ to use `!==` instead – Mark Baker Sep 21 '14 at 12:33
2

Try

foreach (range('A', 'Z') as $char) {
    foreach (range('A', 'Z') as $char1) {
        echo $char . $char1. "\n";
    }
}
Zeusarm
  • 1,038
  • 6
  • 14
1

PHP follows Perl's convention when dealing with arithmetic operations on character variables.

Hence it is possible to increment alphabets in php

$limit = "AZ";

for($x = "A", $limit++; $x != $limit; $x++) {

    echo "$x ";

}

will give you result

A
B
C
.
.
.
AX
AY
AZ

Hope this will help.

Shailesh Sonare
  • 2,791
  • 1
  • 18
  • 14
0

I made a constant time function as follows

This function gives the Alphabetic representation of a numeric index

public static $alpha = ['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'];

public static function getColName($index){
  $index--;
  $nAlphabets = 26;
  $f = floor($index/pow($nAlphabets,0)) % $nAlphabets;
  $s = (floor($index/pow($nAlphabets,1)) % $nAlphabets)-1;
  $t = (floor($index/pow($nAlphabets,2)) % $nAlphabets)-1;

  $f = $f < 0 ? '' : self::$alpha[$f];
  $s = $s < 0 ? '' : self::$alpha[$s];
  $t = $t < 0 ? '' : self::$alpha[$t];

  return trim("{$t}{$s}{$f}");

}

Now if you want to use it create a range. you can call this function in a loop pushing your values to an array.

As for most of the time, we need the representation rather than a range this function would work just fine.

HOW TO USE

Just enclose these static functions in a class and use it as

className::getColName(47);

Making a range in my case was a waste of memory.

For Your Case

for($i = 1; $i < 1000; $i++) $range[] = className::getColName($i);
Abhijit Srivastava
  • 1,419
  • 2
  • 10
  • 33
0

As @Abhijit Srivastava shows, but this is a general way.

function alphaIndex($index) {
    $column = "";
    $nAlphabets = 26;
    $times = (int)($index/$nAlphabets);
    $times = $index%$nAlphabets > 0 ? ($times+1):($times);
    $index--;

    for ($i=0; $i < $times; $i++) { 
        $less = $i > 0 ? 1:0;
        $key = (floor($index/pow($nAlphabets,$i)) % $nAlphabets)-$less;

        $column = ( $key<0 ? '':chr(65+$key) ).$column;
    }

    return $column;
}
-1

I made a custom function that returns an alphabetical range of letters consecutive with a specified amount of letters pass (for example: if you set $pass=2, the function returns [A, C, E, ... AA, AC, AE]).

Another useful option can be $pairs=true that groups all letters into pairs (for example: if you set $pairs=true, the function returns a range of consecutive groups like [[A,B],[C,D],[E,F],...[AA,AB],[AC,AD]] for $pass=1 or [[A,C],[D,F],...[AA,AC],[AD,AF]] for $pass=2).

Call examples:

$myRange = $this->AlphaRange('A','AAZ'); // returns all combinations from A to AAZ,

$myRange = $this->AlphaRange('A','AAZ',2); // returns consecutive combinations from A to AAZ with letters skiped from 2 to 2,

$myRange = $this->AlphaRange('A','AAZ',5,true); // returns consecutive pairs of two letters that contains first and last letter of a group of 5 letters

Hope to be useful.

    public function AlphaRange($from, $to, $pass=1, $pairs=false) {
        $range = [];
        $currStep = 1;
        $nextStep = $pass+1;
        $currPair = 0;

        for($i=$from; $i<'ZZZ'; $i++) {

            if ($currStep == 1) {
                if (false !== $pairs) {
                    $range[$currPair][] = $i;
                }
                else {
                    $range[] = $i;
                }
            }
            else {
                if ($currStep == $nextStep) {

                    if (false !== $pairs) {

                        // $range[count($range[$currPair]) == 2 ? ++$currPair : $currPair][] = $i;

                        $range[$currPair][] = $lastI; 
                        $range[++$currPair][] = $i;

                    }
                    else {
                        $range[]  = $i;
                    }

                    $currStep = 1;
                    $nextStep = $pass+1;
                }
                else {
                    $lastI = $i;
                }                           
            }

            if ($i == $to) {
                if (false !== $pairs) {
                    if (count($range[$currPair]) == 1) {
                        $range[$currPair][] = $i;
                    }
                }
                break;
            }

            $currStep++;
        }

        return $range;
    }
Adrian Covaci
  • 115
  • 1
  • 9